Set-up

Loading packages & custom functions

library(readr)
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(metafor)
Loading required package: Matrix
Loading 'metafor' package (version 2.1-0). For an overview 
and introduction to the package please type: help(metafor).
library(devtools)
Loading required package: usethis
library(purrr)
library(tidyverse)
── Attaching packages ──────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 3.2.0     ✔ tidyr   0.8.3
✔ tibble  2.1.3     ✔ stringr 1.4.0
✔ ggplot2 3.2.0     ✔ forcats 0.4.0
── Conflicts ─────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ tidyr::expand() masks Matrix::expand()
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(tibble)
library(kableExtra)

Attaching package: ‘kableExtra’

The following object is masked from ‘package:dplyr’:

    group_rows
library(robumeta)
library(ggpubr)
Loading required package: magrittr

Attaching package: ‘magrittr’

The following object is masked from ‘package:tidyr’:

    extract

The following object is masked from ‘package:purrr’:

    set_names
library(ggplot2)
library(here)
here() starts at /Users/sz/susi/garvan/Github/IMPC sexDiffs/mice_sex_diff_syd

Functions for preparing the data for meta analyses

  1. “Population statistics”: “calculate_population_stats” This function groups animals from the same strain and same insitiution together. This is done for each trait seoarately, and only for traits that have been measured in both sexes. Any group containing fewer than 5 individuals is excluded.
calculate_population_stats <- function(mydata, min_individuals = 5) {
  mydata %>%
    group_by(population, strain_name, production_center, sex) %>%
    summarise(
      trait = parameter_name[1],
      x_bar = mean(data_point),
      x_sd = sd(data_point),
      n_ind = n()
    ) %>%
    ungroup() %>%
    filter(n_ind > min_individuals) %>%
    # Check both sexes present & filter those missing
    group_by(population) %>%
    mutate(
      n_sex = n_distinct(sex)
    ) %>%
    ungroup() %>%
    filter(n_sex == 2) %>%
    select(-n_sex) %>%
    arrange(production_center, strain_name, population, sex)
}
  1. Extraction of effect sizes and sample variances: “create_meta_analysis_effect_sizes”
create_meta_analysis_effect_sizes <- function(mydata) {
  i <- seq(1, nrow(mydata), by = 2)
  input <- data.frame(
    n1i = mydata$n_ind[i],
    n2i = mydata$n_ind[i + 1],
    x1i = mydata$x_bar[i],
    x2i = mydata$x_bar[i + 1],
    sd1i = mydata$x_sd[i],
    sd2i = mydata$x_sd[i + 1]
  )

  mydata[i, ] %>%
    select(strain_name, production_center, trait) %>%
    mutate(
      effect_size_CVR = calculate_lnCVR(CMean = input$x1i, CSD = input$sd1i, CN = input$n1i, EMean = input$x2i, ESD = input$sd2i, EN = input$n2i),
      sample_variance_CVR = calculate_var_lnCVR(CMean = input$x1i, CSD = input$sd1i, CN = input$n1i, EMean = input$x2i, ESD = input$sd2i, EN = input$n2i),
      effect_size_VR = calculate_lnVR(CSD = input$sd1i, CN = input$n1i, ESD = input$sd2i, EN = input$n2i),
      sample_variance_VR = calculate_var_lnVR(CN = input$n1i, EN = input$n2i),
      effect_size_RR = calculate_lnRR(CMean = input$x1i, CSD = input$sd1i, CN = input$n1i, EMean = input$x2i, ESD = input$sd2i, EN = input$n2i),
      sample_variance_RR = calculate_var_lnRR(CMean = input$x1i, CSD = input$sd1i, CN = input$n1i, EMean = input$x2i, ESD = input$sd2i, EN = input$n2i),
      err = as.factor(seq_len(n()))
    )
}
  1. Calculate meta-analysis statistics

Based on function created by A M Senior @ the University of Otago NZ 03/01/2014:

  • Calculates effect sizes for meta-analysis of variance. All functions take the mean, sd and n from the control and experimental groups.
  • The first function, calculate_lnCVR, calculates the the log response-ratio of the coefficient of variance (lnCVR) - see Nakagawa et al 2015.
  • The second function calculates the measurement error variance for lnCVR. As well as the aforementioned parameters, this function also takes Equal_E_C_Corr (default = T), which must be True or False. If true, the function assumes that the correlation between mean and sd (Taylor’s Law) is equal for the mean and control groups, and, thus these data are pooled. If False the mean-SD correlation for the experimental and control groups are calculated separately from one another.
  • Similar functions are then implemented for lnVR (for comparison of standard deviations) and ln RR (for comparison of means)

calculate_lnCVR <- function(CMean, CSD, CN, EMean, ESD, EN) {
  log(ESD) - log(EMean) + 1 / (2 * (EN - 1)) - (log(CSD) - log(CMean) + 1 / (2 * (CN - 1)))
}

calculate_var_lnCVR <- function(CMean, CSD, CN, EMean, ESD, EN, Equal_E_C_Corr = T) {
  if (Equal_E_C_Corr == T) {
    mvcorr <- 0 # cor.test(log(c(CMean, EMean)), log(c(CSD, ESD)))$estimate   old, slightly incorrect
    S2 <- CSD^2 / (CN * (CMean^2)) + 1 / (2 * (CN - 1)) - 2 * mvcorr * sqrt((CSD^2 / (CN * (CMean^2))) * (1 / (2 * (CN - 1)))) + ESD^2 / (EN * (EMean^2)) + 1 / (2 * (EN - 1)) - 2 * mvcorr * sqrt((ESD^2 / (EN * (EMean^2))) * (1 / (2 * (EN - 1))))
  }
  else {
    Cmvcorr <- cor.test(log(CMean), log(CSD))$estimate
    Emvcorr <- cor.test(log(EMean), (ESD))$estimate
    S2 <- CSD^2 / (CN * (CMean^2)) + 1 / (2 * (CN - 1)) - 2 * Cmvcorr * sqrt((CSD^2 / (CN * (CMean^2))) * (1 / (2 * (CN - 1)))) + ESD^2 / (EN * (EMean^2)) + 1 / (2 * (EN - 1)) - 2 * Emvcorr * sqrt((ESD^2 / (EN * (EMean^2))) * (1 / (2 * (EN - 1))))
  }
  S2
}

calculate_lnVR <- function(CSD, CN, ESD, EN) {
  log(ESD) - log(CSD) + 1 / (2 * (EN - 1)) - 1 / (2 * (CN - 1))
}

calculate_var_lnVR <- function(CN, EN) {
  1 / (2 * (EN - 1)) + 1 / (2 * (CN - 1))
}

calculate_lnRR <- function(CMean, CSD, CN, EMean, ESD, EN) {
  log(EMean) - log(CMean)
}

calculate_var_lnRR <- function(CMean, CSD, CN, EMean, ESD, EN) {
  CSD^2 / (CN * CMean^2) + ESD^2 / (EN * EMean^2)
}

Load & clean data

  1. Data loading and cleaning of the csv file

This step we have already done and provide a cleaned up file which is less computing intensive and which we have saved in a folder called export. However, the cvs is provided in case this is preferred to be attempted, following the steps below:

# loads the raw data, setting some default types for various columns

load_raw <- function(filename) {
  read_csv(filename,
    col_types = cols(
      .default = col_character(),
      project_id = col_character(),
      id = col_character(),
      parameter_id = col_character(),
      age_in_days = col_integer(),
      date_of_experiment = col_datetime(format = ""),
      weight = col_double(),
      phenotyping_center_id = col_character(),
      production_center_id = col_character(),
      weight_date = col_datetime(format = ""),
      date_of_birth = col_datetime(format = ""),
      procedure_id = col_character(),
      pipeline_id = col_character(),
      biological_sample_id = col_character(),
      biological_model_id = col_character(),
      weight_days_old = col_integer(),
      datasource_id = col_character(),
      experiment_id = col_character(),
      data_point = col_double(),
      age_in_weeks = col_integer(),
      `_version_` = col_character()
    )
  )
}

# Apply some standard cleaning to the data
clean_raw_data <- function(mydata) {
  
  group <- read_csv(here("data", "ParameterGrouping.csv"))
  
  tmp <- 
    mydata %>%

    # Filter to IMPC source (recommend by Jeremey in email to Susi on 20 Aug 2018)
    filter(datasource_name == "IMPC") %>%

    # standardise trait names
    mutate(parameter_name = tolower(parameter_name)) %>%

    # remove extreme ages
    filter(age_in_days > 0 & age_in_days < 500) %>%

    # remove NAs
    filter(!is.na(data_point)) %>%

    # subset to reasonable set of variables
    # date_of_experiment: Jeremy suggested using as an indicator of batch-level effects
    select(production_center, strain_name, strain_accession_id, biological_sample_id, pipeline_stable_id, procedure_group, procedure_name, sex, date_of_experiment, age_in_days, weight, parameter_name, data_point) %>% 

    # sort
    arrange(production_center, biological_sample_id, age_in_days)
      
    # filter to groups with > 1 centre  
    # **Review** - retaining merge here to retain ordering of data used in previous version
    # usually i would use mutate instead of creating sperate dataset
    merge(tmp, 
          tmp %>% group_by(parameter_name) %>%
    summarise(center_per_trait = length(unique(production_center, na.rm = TRUE)))
        )%>%
    filter(center_per_trait >= 2) %>% 

    # Define population variable
    mutate(population = sprintf("%s-%s", production_center, strain_name)) %>% 

    # add grouping variable: these were decided based on functional groups and procedures 
    mutate(parameter_group = group$parameter[match(parameter_name, group$parameter_name)] ) %>%
    # usually i would use left_join
        # left_join(by="parameter_name", 
    #   read_csv(here("data", "ParameterGrouping.csv")) %>%
    #     select(-id)
    # ) %>%
          
    # Assign unique IDs (per trait)
    # each unique parameter_name (=trait,use trait variable) gets a unique number ('id')

    # We add a new variable, where redundant traits are combined
    #[note however, at this stage the dataset still contains nonsensical traits, i.e. traits that may not contain any information on variance]
    mutate(id = match(parameter_name, unique(parameter_name))) %>% 
    as_tibble()
}

# Load raw data - save cleaned dataset as RDS for reuse
data_raw <- load_raw(here("data","dr7.0_all_control_data.csv.gz"))
dir.create("export", F, F)

data <- data_raw %>% 
  clean_raw_data() 
saveRDS(data, "export/data_clean.rds")

For analysis we load the RDS created above and other datasets:

data <- readRDS(here("export", "data_clean.rds")) 

procedures <- read_csv(here("data", "procedures.csv"))
Parsed with column specification:
cols(
  procedure = col_character(),
  GroupingTerm = col_character()
)

Check length of different variables / sample sizes:

length(unique(data$parameter_name)) # 232 traits
[1] 232
length(unique(data$parameter_group)) # 161 parameter groups
[1] 161
length(unique(data$procedure_name)) # 26 procedure groups
[1] 26
length(unique(data$biological_sample_id)) # 27147 individial mice   #FZ added 11-12-2019
[1] 27147
#number of males and females per strain per production center #FZ added 11-12-2019
data %>% group_by(production_center, strain_name) %>% count(biological_sample_id, sex) %>% count(sex) %>% print(n = Inf)
NA
NA

Phase 1: across all traits

Create function for sub-setting the data to choose only one data point per individual per trait. This is a necessary step for the loop across all traits


data_subset_parameterid_individual_by_age <- function(mydata, parameter, age_min=0, age_center=100) {
  tmp <- mydata %>%
    filter(
      age_in_days >= age_min,
      id == parameter
    ) %>%
    # take results for single individual closest to age_center
    mutate(age_diff = abs(age_center - age_in_days)) %>%
    group_by(biological_sample_id) %>%
    filter(age_diff == min(age_diff)) %>%
    select(-age_diff)# %>% 
#    filter(!duplicated(biological_sample_id))

    
  # still some individuals with multiple records (because same individual appear under different procedures, so filter to one record)
  j <- match(unique(tmp$biological_sample_id), tmp$biological_sample_id)
  tmp[j, ] 
  }

Loop running meta-analysis on all traits

for (t in 1:n) {
  tryCatch(
    {
      results <- data %>% 
        data_subset_parameterid_individual_by_age(t) %>%
        calculate_population_stats() %>%
        create_meta_analysis_effect_sizes()

      # lnCVR,  log repsonse-ratio of the coefficient of variance
      cvr <- metafor::rma.mv(yi = effect_size_CVR, V = sample_variance_CVR, 
                             random = list(~ 1 | strain_name, ~ 1 | production_center, ~ 1 | err), 
                             control = list(optimizer = "optim", optmethod = "Nelder-Mead", 
                                            maxit = 1000), verbose = F, data = results)

      # lnVR, comparison of standard deviations
      cv <- metafor::rma.mv(yi = effect_size_VR, V = sample_variance_VR,
                            random = list(~ 1 | strain_name, ~ 1 | production_center, ~ 1 | err), 
                            control = list(optimizer = "optim", optmethod = "Nelder-Mead", 
                                           maxit = 1000), verbose = F, data = results)

      # for means, lnRR
      means <- metafor::rma.mv(yi = effect_size_RR, V = sample_variance_RR, 
                               random = list(~ 1 | strain_name, ~ 1 | production_center, ~ 1 | err), 
                               control = list(optimizer = "optim", optmethod = "Nelder-Mead", 
                                              maxit = 1000), verbose = F, data = results)
      
      f <- function(x) unlist(x[c("b", "ci.lb", "ci.ub", "se")])

      results_alltraits_grouping[t, 2:14] <- c(f(cvr), f(cv), f(means), means$k)
      results_alltraits_grouping[t, 15] <- unique(results$trait)
    },
    error = function(e) {
      cat("ERROR :", t, conditionMessage(e), "\n")
    }
  )
}
ERROR : 84 Optimizer (optim) did not achieve convergence (convergence = 10). 
Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Rows with NAs omitted from model fitting.Rows with NAs omitted from model fitting.Rows with NAs omitted from model fitting.Rows with NAs omitted from model fitting.Rows with NAs omitted from model fitting.There are outcomes with non-positive sampling variances.'V' appears to be not positive definite.
ERROR : 158 Optimizer (optim) did not achieve convergence (convergence = 10). 
Rows with NAs omitted from model fitting.
ERROR : 160 NA/NaN/Inf in 'y' 
Rows with NAs omitted from model fitting.
ERROR : 161 NA/NaN/Inf in 'y' 
Rows with NAs omitted from model fitting.
ERROR : 162 NA/NaN/Inf in 'y' 
Rows with NAs omitted from model fitting.
ERROR : 163 NA/NaN/Inf in 'y' 
Rows with NAs omitted from model fitting.
ERROR : 165 NA/NaN/Inf in 'y' 
Rows with NAs omitted from model fitting.
ERROR : 166 NA/NaN/Inf in 'y' 
Rows with NAs omitted from model fitting.Rows with NAs omitted from model fitting.There are outcomes with non-positive sampling variances.'V' appears to be not positive definite.Rows with NAs omitted from model fitting.
ERROR : 168 NA/NaN/Inf in 'y' 
Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Single-level factor(s) found in 'random' argument. Corresponding 'sigma2' value(s) fixed to 0.Rows with NAs omitted from model fitting.Rows with NAs omitted from model fitting.There are outcomes with non-positive sampling variances.'V' appears to be not positive definite.Rows with NAs omitted from model fitting.Rows with NAs omitted from model fitting.There are outcomes with non-positive sampling variances.'V' appears to be not positive definite.Rows with NAs omitted from model fitting.
ERROR : 231 NA/NaN/Inf in 'y' 
REVIEW: The above loop gives some errors, can these be fixed? FZ: In the above function, we use ‘tryCatch’ and ‘conditionMessage’ to prevent the loop from aborting when the first error at row 84 is produced. FZ Convergence in the two listed non-converging cases can’t be achieved by sensibly tweaking (other optim etc.). FZ Since we only learn about non-convergence in the loop, it’s difficult to exclude the two traits beforehand. FZ Similarly, the 8 traits with very low variation (160, …, 231) are hard to exclude before. FZ Warnings are ok: indicating cases where variance components are set to zero during likelihood optimization.
ERROR : 84 Optimizer (optim) did not achieve convergence (convergence = 10). ERROR : 158 Optimizer (optim) did not achieve convergence (convergence = 10). ERROR : 160 NA/NaN/Inf in ‘y’ ERROR : 161 NA/NaN/Inf in ‘y’ ERROR : 162 NA/NaN/Inf in ‘y’ ERROR : 163 NA/NaN/Inf in ‘y’ ERROR : 165 NA/NaN/Inf in ‘y’ ERROR : 166 NA/NaN/Inf in ‘y’ ERROR : 168 NA/NaN/Inf in ‘y’ ERROR : 231 NA/NaN/Inf in ‘y’
Also a bunch of warnings, are any of these a concern?
> warnings() Warning messages: 1: In metafor::rma.mv(yi = effect_size_CVR, V = sample_variance_CVR, … : Rows with NAs omitted from model fitting. … 13: In metafor::rma.mv(yi = effect_size_RR, V = sample_variance_RR, … : There are outcomes with non-positive sampling variances. 14: In metafor::rma.mv(yi = effect_size_RR, V = sample_variance_RR, … : ‘V’ appears to be not positive definite. 16: In metafor::rma.mv(yi = effect_size_CVR, V = sample_variance_CVR, … : Single-level factor(s) found in ‘random’ argument. Corresponding ‘sigma2’ value(s) fixed to 0. … 50: In metafor::rma.mv(yi = effect_size_RR, V = sample_variance_RR, … : ‘V’ appears to be not positive definite

Now that we have a “results” table with each of the meta-analytic means for all effect sizes of interest, we can use this table as part of the Shiny App, which will then be able to back calculate the percentage differences between males and females for mean, variance and coefficient of variance. We’ll export and use this in the Shiny App. Note that I have not dealt with convergence issues in some of these models, and so, this will need to be done down the road

(Note Susi 31/7/2019: This dataset contains dublicated values, plus no info on what the “traits” mean. I will change Dan N’s to one further belwo, that have been cleaned up already FILE TO USE: METACOMBO (around line 500))

Merging datasets & removal of non-converged traits

Procedure names, grouping variables etc. are merged back together with the results from the metafor analysis above. This requires loading of another excel sheet, “procedures.csv”

n
[1] 232

Removal of traits that did not achieve convergence, are nonsensical for analysis of variance (such as traits that show variation, such as number of ribs, digits, etc). 14 traits from the originally 232 that had been included are removed.

Review: How did we determine this the ones with problems? FZ: In addition to the sentence one line above, to do: add information about cause of exclusion ( 1. non-convergence of metafor models, or 2. no variation/nonsensical); reference traits to be excluded by trait name (not id number) FZ: excluded because of non-convergence: 84, 158 FZ: excluded because no variation/nonsensical: 144, 158, 160,…

results_alltraits_grouping2 <- 
  results_alltraits_grouping %>% 
  left_join(by="id",
             data %>% select(id, parameter_group, procedure = procedure_name, procedure_name) %>% #susi: check parateer group
              # REVIEW -- this bext line replciates precious code, but removes some procedures, is that right?
          # FZ: No. This creates the data from the complete data set ('data'), which was not carried over into 'results_alltraits_grouping'
          # FZ: We filter duplicated id's to get only one unique row per id (and there is one id per parameter_name)
              filter(!duplicated(id))
            ) %>%
  # FZ: Below we add 'procedure' (from the previously loaded 'procedures.csv') as a variable
  left_join(by="procedure", 
            procedures %>% distinct()
            )
  

n <- length(unique(results_alltraits_grouping2$parameter_name)) # 232
Unknown or uninitialised column: 'parameter_name'.

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoiRXJyb3I6IGF0dGVtcHQgdG8gdXNlIHplcm8tbGVuZ3RoIHZhcmlhYmxlIG5hbWVcbiJ9 -->

Error: attempt to use zero-length variable name




<!-- rnb-output-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->

Reveiw: check against old script – identical, remove once fixed

meta_clean.test <- readRDS("../meta_clean.test.rds")  #FZ comment: doesn't work for me. '../' is for the github location?
all.equal(meta_clean, meta_clean.test)
all.equal(meta_clean %>% select(-parameter_group), meta_clean.test %>% mutate(id=as.integer(id), GroupingTerm = as.character(GroupingTerm)))

Meta-analysis, Phase 2: non-independent traits

Dealing with Correlated Parameters, preparation

This dataset contained a number of highly correlated traits, such as different kinds of cell counts (for example, hierarchical parameterization within immunological assays). As those data-points are not independent of each other, we conducted a meta analyses on these correlated parameters to collapse the number of levels.

Collapsing and merging correlated parameters

Here we double check numbers of trait parameters in the dataset


meta1 <- meta_clean
length(unique(meta1$procedure)) #18
length(unique(meta1$GroupingTerm)) #9
# Review: next line now 155 not 148 #FZ comment: still 148 for me.
length(unique(meta1$parameter_group)) # 148 levels. To be used as grouping factor for meta-meta analysis / collapsing down based on things that are classified identically in "parameter_group" but have different "parameter_name"
length(unique(meta1$parameter_name)) #218

Count of number of parameter names (correlated sub-traits) in each parameter group (par_group_size)

This serves to identify and separate the traits that are correlated from the full dataset that can be processed as is. If the sample size (n) for a given “parameter group” equals 1, the trait is unique and uncorrelated. All instances, where there are 2 or more traits associated with the same parameter group (90 cases), are selected for a “mini-meta analysis”, which removes the issue of correlation.


kable(cbind(meta1 %>% count(parameter_group))) %>%
  kable_styling() %>%
  scroll_box(width = "100%", height = "200px")
meta1_sub <- meta1 %>%
  # add summary of number of parameter names in each parameter group
  group_by(parameter_group) %>%
  mutate(par_group_size = length(unique(parameter_name)), 
         sampleSize = as.numeric(sampleSize)) %>% 
  ungroup() %>% 
  # Create subsets with > 1 count (par_group_size > 1)
  filter(par_group_size > 1) # 90 observations

Meta-analyses on correlated (sub-)traits, using robumeta`

The subset of the data is prepared (nested), and in this first step the model of the meta analysis effect sizes are calculated



meta1b <-
  meta1 %>%
  group_by(parameter_group) %>% 
  summarize(par_group_size = length(unique(parameter_name, na.rm = TRUE)))
#this gives a summary of number of parameter names in each parameter group, now it neeeds to get merged it back together


meta1$par_group_size <- meta1b$par_group_size[match(meta1$parameter_group, meta1b$parameter_group)]

# Create subsets with > 1 count (par_group_size > 1) 

meta1_sub <- subset(meta1,par_group_size >1) # 90 observations   
meta1_sub$sampleSize <- as.numeric(meta1_sub$sampleSize)

# nesting
n_count <- meta1_sub %>%
  group_by(parameter_group) %>%
  mutate(raw_N = sum(sampleSize)) %>%
  nest() %>%
  ungroup()

model_count <- n_count %>%
  mutate(
    model_lnRR = map(data, ~ robu(.x$lnRR ~ 1, data = .x, studynum = .x$id, modelweights = c("CORR"), rho = 0.8, small = TRUE, var.eff.size = (.x$lnRR_se)^2)),
    model_lnVR = map(data, ~ robu(.x$lnVR ~ 1, data = .x, studynum = .x$id, modelweights = c("CORR"), rho = 0.8, small = TRUE, var.eff.size = (.x$lnVR_se)^2)),
    model_lnCVR = map(data, ~ robu(.x$lnCVR ~ 1, data = .x, studynum = .x$id, modelweights = c("CORR"), rho = 0.8, small = TRUE, var.eff.size = (.x$lnCVR_se)^2))
  )

Extract and save parameter estimates: Function to collect the outcomes of the “mini” meta analysis

count_fun <- function(mod_sub) {
  return(c(mod_sub$reg_table$b.r, mod_sub$reg_table$CI.L, mod_sub$reg_table$CI.U, mod_sub$reg_table$SE))
} # estimate, lower ci, upper ci, SE

Extraction of values created during Meta analysis using robu meta:

robusub_RR <- model_count %>%
  transmute(parameter_group, estimatelnRR = map(model_lnRR, count_fun)) %>%
  mutate(r = map(estimatelnRR, ~ data.frame(t(.)))) %>%
  unnest(r) %>%
  select(-estimatelnRR) %>%
  purrr::set_names(c("parameter_group", "lnRR", "lnRR_lower", "lnRR_upper", "lnRR_se"))

robusub_CVR <- model_count %>%
  transmute(parameter_group, estimatelnCVR = map(model_lnCVR, count_fun)) %>%
  mutate(r = map(estimatelnCVR, ~ data.frame(t(.)))) %>%
  unnest(r) %>%
  select(-estimatelnCVR) %>%
  purrr::set_names(c("parameter_group", "lnCVR", "lnCVR_lower", "lnCVR_upper", "lnCVR_se"))

robusub_VR <- model_count %>%
  transmute(parameter_group, estimatelnVR = map(model_lnVR, count_fun)) %>%
  mutate(r = map(estimatelnVR, ~ data.frame(t(.)))) %>%
  unnest(r) %>%
  select(-estimatelnVR) %>%
  purrr::set_names(c("parameter_group", "lnVR", "lnVR_lower", "lnVR_upper", "lnVR_se"))

robu_all <- full_join(robusub_CVR, robusub_VR) %>% full_join(., robusub_RR)
kable(cbind(robu_all, robu_all)) %>%
  kable_styling() %>%
  scroll_box(width = "100%", height = "200px")

Merge the two data sets (the new [robu_all] and the initial [uncorrelated sub-traits with count = 1])

meta_all <- meta1 %>%
  filter(par_group_size == 1) %>%
  as_tibble()
# str(meta_all)
# str(robu_all)
# which(is.na(match(names(meta_all),names(robu_all))))  # check

Combine data

# Step1 (columns are matched by name (in our case, 'parameter_group'), and any missing columns will be filled with NA) #FZ added explanation of bibd_rows
combinedmeta <- bind_rows(robu_all, meta_all)
# glimpse(combinedmeta)

# Steps 2&3 (add information about number of traits in a parameter group, procedure, and grouping term) #FZ added expalnation in brackets
metacombo <- combinedmeta
metacombo$counts <- meta1$par_group_size[match(metacombo$parameter_group, meta1$parameter_group)] 
metacombo$procedure2 <- meta1$procedure[match(metacombo$parameter_group, meta1$parameter_group)]
metacombo$GroupingTerm2 <- meta1$GroupingTerm[match(metacombo$parameter_group, meta1$parameter_group)]

kable(cbind(metacombo, metacombo)) %>%
  kable_styling() %>%
  scroll_box(width = "100%", height = "200px")

Clean-up, reorder, and rename

metacombo <- metacombo[, c(1, 21:23, 2:13)] # SUSI CHANGE TO NAMES!!!
names(metacombo)[3] <- "procedure" #change "3" to name
names(metacombo)[4] <- "GroupingTerm" #change "4" to name

# Quick pre-check before doing plots

metacombo %>%
  group_by(GroupingTerm) %>%
  dplyr::summarize(MeanCVR = mean(lnCVR), MeanVR = mean(lnVR), MeanRR = mean(lnRR))
# SHINY APP # Now that we have a corrected "results" table with each of the meta-analytic means for all effect sizes of interest, we can use this table as part of the Shiny App, which will then be able to back calculate the percentage differences between males and females for mean, variance and coefficient of variance. We'll export and use this in the Shiny App. **Note that I have not dealt with convergence issues in some of these models, and so, this will need to be done down the road**

## Note Susi 31/7/2019: This has been cleaned up already
# FILE TO USE: METACOMBO
### note: to use

# trait_meta_results <- write.csv(metacombo, file = "export/trait_meta_results.csv")

Meta-analysis, Phase 3: Second-order meta analysis for functional groups

Perform meta-analyses (3 for each of the 9 grouping terms: lnCVR, lnVR, lnRR)

This is the full result dataset


kable(cbind(metacombo, metacombo)) %>%
  kable_styling() %>%
  scroll_box(width = "100%", height = "200px")

Prepare data

Nesting, calculating the number of parameters within each grouping term, and running the meta-analysis

metacombo_final <- metacombo %>%
  group_by(GroupingTerm) %>%
#FZ comment: changed 'nest' to 'nest_legacy' to keep old syntax/functionality
  nest_legacy()


# **calculate number of parameters per grouping term

metacombo_final <- metacombo_final %>% mutate(para_per_GroupingTerm = map_dbl(data, nrow))

# For all grouping terms
metacombo_final_all <- metacombo %>%
#FZ comment: changed 'nest' to 'nest_legacy' to keep old syntax/functionality
  nest_legacy()

# **Final fixed effects meta-analyses within grouping terms, with SE of the estimate

overall1 <- metacombo_final %>%

  mutate(
    model_lnCVR = map(data, ~ metafor::rma.uni(
      yi = .x$lnCVR, sei = (.x$lnCVR_upper - .x$lnCVR_lower) / (2 * 1.96),
      control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
    )),
    model_lnVR = map(data, ~ metafor::rma.uni(
      yi = .x$lnVR, sei = (.x$lnVR_upper - .x$lnVR_lower) / (2 * 1.96),
      control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
    )),
    model_lnRR = map(data, ~ metafor::rma.uni(
      yi = .x$lnRR, sei = (.x$lnRR_upper - .x$lnRR_lower) / (2 * 1.96),
      control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
    ))
  )

# **Final fixed effects meta-analyses ACROSS grouping terms, with SE of the estimate

overall_all1 <- metacombo_final_all %>%

  mutate(
    model_lnCVR = map(data, ~ metafor::rma.uni(
      yi = .x$lnCVR, sei = (.x$lnCVR_upper - .x$lnCVR_lower) / (2 * 1.96),
      control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
    )),
    model_lnVR = map(data, ~ metafor::rma.uni(
      yi = .x$lnVR, sei = (.x$lnVR_upper - .x$lnVR_lower) / (2 * 1.96),
      control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
    )),
    model_lnRR = map(data, ~ metafor::rma.uni(
      yi = .x$lnRR, sei = (.x$lnRR_upper - .x$lnRR_lower) / (2 * 1.96),
      control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
    ))
  )

Re-structure data for each grouping term; delete unused variables #FZ comment: referencing of cells below doesn’t depend on previous oreding of the data, i.e. only changes if output structure from metafor::rma.uni changes

Behaviour <- as.data.frame(overall1 %>% filter(., GroupingTerm == "Behaviour") %>% mutate(
  lnCVR = .[[4]][[1]]$b, lnCVR_lower = .[[4]][[1]]$ci.lb, lnCVR_upper = .[[4]][[1]]$ci.ub, lnCVR_se = .[[4]][[1]]$se,
  lnVR = .[[5]][[1]]$b, lnVR_lower = .[[5]][[1]]$ci.lb, lnVR_upper = .[[5]][[1]]$ci.ub, lnVR_se = .[[5]][[1]]$se,
  lnRR = .[[6]][[1]]$b, lnRR_lower = .[[6]][[1]]$ci.lb, lnRR_upper = .[[6]][[1]]$ci.ub, lnRR_se = .[[6]][[1]]$se
))[, c(1, 7:18)]

Immunology <- as.data.frame(overall1 %>% filter(., GroupingTerm == "Immunology") %>% mutate(
  lnCVR = .[[4]][[1]]$b, lnCVR_lower = .[[4]][[1]]$ci.lb, lnCVR_upper = .[[4]][[1]]$ci.ub, lnCVR_se = .[[4]][[1]]$se,
  lnVR = .[[5]][[1]]$b, lnVR_lower = .[[5]][[1]]$ci.lb, lnVR_upper = .[[5]][[1]]$ci.ub, lnVR_se = .[[5]][[1]]$se,
  lnRR = .[[6]][[1]]$b, lnRR_lower = .[[6]][[1]]$ci.lb, lnRR_upper = .[[6]][[1]]$ci.ub, lnRR_se = .[[6]][[1]]$se
))[, c(1, 7:18)]

Hematology <- as.data.frame(overall1 %>% filter(., GroupingTerm == "Hematology") %>% mutate(
  lnCVR = .[[4]][[1]]$b, lnCVR_lower = .[[4]][[1]]$ci.lb, lnCVR_upper = .[[4]][[1]]$ci.ub, lnCVR_se = .[[4]][[1]]$se,
  lnVR = .[[5]][[1]]$b, lnVR_lower = .[[5]][[1]]$ci.lb, lnVR_upper = .[[5]][[1]]$ci.ub, lnVR_se = .[[5]][[1]]$se,
  lnRR = .[[6]][[1]]$b, lnRR_lower = .[[6]][[1]]$ci.lb, lnRR_upper = .[[6]][[1]]$ci.ub, lnRR_se = .[[6]][[1]]$se
))[, c(1, 7:18)]

Hearing <- as.data.frame(overall1 %>% filter(., GroupingTerm == "Hearing") %>% mutate(
  lnCVR = .[[4]][[1]]$b, lnCVR_lower = .[[4]][[1]]$ci.lb, lnCVR_upper = .[[4]][[1]]$ci.ub, lnCVR_se = .[[4]][[1]]$se,
  lnVR = .[[5]][[1]]$b, lnVR_lower = .[[5]][[1]]$ci.lb, lnVR_upper = .[[5]][[1]]$ci.ub, lnVR_se = .[[5]][[1]]$se,
  lnRR = .[[6]][[1]]$b, lnRR_lower = .[[6]][[1]]$ci.lb, lnRR_upper = .[[6]][[1]]$ci.ub, lnRR_se = .[[6]][[1]]$se
))[, c(1, 7:18)]

Physiology <- as.data.frame(overall1 %>% filter(., GroupingTerm == "Physiology") %>% mutate(
  lnCVR = .[[4]][[1]]$b, lnCVR_lower = .[[4]][[1]]$ci.lb, lnCVR_upper = .[[4]][[1]]$ci.ub, lnCVR_se = .[[4]][[1]]$se,
  lnVR = .[[5]][[1]]$b, lnVR_lower = .[[5]][[1]]$ci.lb, lnVR_upper = .[[5]][[1]]$ci.ub, lnVR_se = .[[5]][[1]]$se,
  lnRR = .[[6]][[1]]$b, lnRR_lower = .[[6]][[1]]$ci.lb, lnRR_upper = .[[6]][[1]]$ci.ub, lnRR_se = .[[6]][[1]]$se
))[, c(1, 7:18)]

Metabolism <- as.data.frame(overall1 %>% filter(., GroupingTerm == "Metabolism") %>% mutate(
  lnCVR = .[[4]][[1]]$b, lnCVR_lower = .[[4]][[1]]$ci.lb, lnCVR_upper = .[[4]][[1]]$ci.ub, lnCVR_se = .[[4]][[1]]$se,
  lnVR = .[[5]][[1]]$b, lnVR_lower = .[[5]][[1]]$ci.lb, lnVR_upper = .[[5]][[1]]$ci.ub, lnVR_se = .[[5]][[1]]$se,
  lnRR = .[[6]][[1]]$b, lnRR_lower = .[[6]][[1]]$ci.lb, lnRR_upper = .[[6]][[1]]$ci.ub, lnRR_se = .[[6]][[1]]$se
))[, c(1, 7:18)]

Morphology <- as.data.frame(overall1 %>% filter(., GroupingTerm == "Morphology") %>% mutate(
  lnCVR = .[[4]][[1]]$b, lnCVR_lower = .[[4]][[1]]$ci.lb, lnCVR_upper = .[[4]][[1]]$ci.ub, lnCVR_se = .[[4]][[1]]$se,
  lnVR = .[[5]][[1]]$b, lnVR_lower = .[[5]][[1]]$ci.lb, lnVR_upper = .[[5]][[1]]$ci.ub, lnVR_se = .[[5]][[1]]$se,
  lnRR = .[[6]][[1]]$b, lnRR_lower = .[[6]][[1]]$ci.lb, lnRR_upper = .[[6]][[1]]$ci.ub, lnRR_se = .[[6]][[1]]$se
))[, c(1, 7:18)]

Heart <- as.data.frame(overall1 %>% filter(., GroupingTerm == "Heart") %>% mutate(
  lnCVR = .[[4]][[1]]$b, lnCVR_lower = .[[4]][[1]]$ci.lb, lnCVR_upper = .[[4]][[1]]$ci.ub, lnCVR_se = .[[4]][[1]]$se,
  lnVR = .[[5]][[1]]$b, lnVR_lower = .[[5]][[1]]$ci.lb, lnVR_upper = .[[5]][[1]]$ci.ub, lnVR_se = .[[5]][[1]]$se,
  lnRR = .[[6]][[1]]$b, lnRR_lower = .[[6]][[1]]$ci.lb, lnRR_upper = .[[6]][[1]]$ci.ub, lnRR_se = .[[6]][[1]]$se
))[, c(1, 7:18)]

Eye <- as.data.frame(overall1 %>% filter(., GroupingTerm == "Eye") %>% mutate(
  lnCVR = .[[4]][[1]]$b, lnCVR_lower = .[[4]][[1]]$ci.lb, lnCVR_upper = .[[4]][[1]]$ci.ub, lnCVR_se = .[[4]][[1]]$se,
  lnVR = .[[5]][[1]]$b, lnVR_lower = .[[5]][[1]]$ci.lb, lnVR_upper = .[[5]][[1]]$ci.ub, lnVR_se = .[[5]][[1]]$se,
  lnRR = .[[6]][[1]]$b, lnRR_lower = .[[6]][[1]]$ci.lb, lnRR_upper = .[[6]][[1]]$ci.ub, lnRR_se = .[[6]][[1]]$se
))[, c(1, 7:18)]

All <- as.data.frame(overall_all1 %>% mutate(
  lnCVR = .[[2]][[1]]$b, lnCVR_lower = .[[2]][[1]]$ci.lb, lnCVR_upper = .[[2]][[1]]$ci.ub, lnCVR_se = .[[2]][[1]]$se, lnVR = .[[3]][[1]]$b, lnVR_lower = .[[3]][[1]]$ci.lb, lnVR_upper = .[[3]][[1]]$ci.ub, lnVR_se = .[[3]][[1]]$se,
  lnRR = .[[4]][[1]]$b, lnRR_lower = .[[4]][[1]]$ci.lb, lnRR_upper = .[[4]][[1]]$ci.ub, lnRR_se = .[[4]][[1]]$se
))[, c(5:16)]

All$lnCVR <- as.numeric(All$lnCVR)
All$lnVR <- as.numeric(All$lnVR)
All$lnRR <- as.numeric(All$lnRR)
All <- All %>% mutate(GroupingTerm = "All")

overall2 <- bind_rows(Behaviour, Morphology, Metabolism, Physiology, Immunology, Hematology, Heart, Hearing, Eye, All) #FZ: warnings are ok

Visualisation

Preparation for plots: Count data, based on First-order meta analysis results

Re-order grouping terms


meta_clean$GroupingTerm <- factor(meta_clean$GroupingTerm, levels = c("Behaviour", "Morphology", "Metabolism", "Physiology", "Immunology", "Hematology", "Heart", "Hearing", "Eye"))
meta_clean$GroupingTerm <- factor(meta_clean$GroupingTerm, rev(levels(meta_clean$GroupingTerm)))

# *Prepare data for all traits

meta.plot2.all <- meta_clean %>%
  select(lnCVR, lnVR, lnRR, GroupingTerm) %>%
  arrange(GroupingTerm)

meta.plot2.all.b <- gather(meta.plot2.all, trait, value, c(lnCVR, lnRR)) # lnVR,

meta.plot2.all.b$trait <- factor(meta.plot2.all.b$trait, levels = c("lnCVR", "lnRR")) # "lnVR",

meta.plot2.all.c <- meta.plot2.all.b %>%
  group_by_at(vars(trait, GroupingTerm)) %>%
  summarise(
    malebias = sum(value > 0), femalebias = sum(value <= 0), total = malebias + femalebias,
    malepercent = malebias * 100 / total, femalepercent = femalebias * 100 / total
  )

meta.plot2.all.c$label <- "All traits"

# restructure to create stacked bar plots

meta.plot2.all.d <- as.data.frame(meta.plot2.all.c)
meta.plot2.all.e <- gather(meta.plot2.all.d, key = sex, value = percent, malepercent:femalepercent, factor_key = TRUE)

# create new sample size variable

meta.plot2.all.e$samplesize <- with(meta.plot2.all.e, ifelse(sex == "malepercent", malebias, femalebias))

# add summary row ('All') and re-arrange rows into correct order for plotting #FZ added

meta.plot2.all.f <- meta.plot2.all.e %>% group_by(trait, sex) %>% 
    summarise(GroupingTerm = "All", malebias = sum(malebias), femalebias = sum(femalebias), total = malebias + femalebias, 
    label = "All traits", samplesize = sum(samplesize)) %>%
    mutate(percent = ifelse(sex == "femalepercent", femalebias*100/(malebias+femalebias), malebias*100/(malebias+femalebias))) %>%
    bind_rows(meta.plot2.all.e, .) %>%
    mutate(rownumber = row_number()) %>%
    .[c(37, 1:9, 39, 10:18, 38, 19:27, 40, 28:36), ]

meta.plot2.all.f$GroupingTerm <- factor(meta.plot2.all.f$GroupingTerm, levels = c("Behaviour", "Morphology", "Metabolism", "Physiology", "Immunology", "Hematology", "Heart", "Hearing", "Eye", "All")) 
meta.plot2.all.f$GroupingTerm <- factor(meta.plot2.all.f$GroupingTerm, rev(levels(meta.plot2.all.f$GroupingTerm)))

malebias_Fig2_alltraits <-
  ggplot(meta.plot2.all.f) +
  aes(x = GroupingTerm, y = percent, fill = sex) +
  geom_col() +
  geom_hline(yintercept = 50, linetype = "dashed", color = "gray40") +
  geom_text(
    data = subset(meta.plot2.all.f, samplesize != 0), aes(label = samplesize), position = position_stack(vjust = .5),
    color = "white", size = 3.5
  ) +
  facet_grid(
    cols = vars(trait), rows = vars(label), labeller = label_wrap_gen(width = 18),
    scales = "free", space = "free"
  ) +
  scale_fill_brewer(palette = "Set2") +
  theme_bw(base_size = 18) +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.position = "none",
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  ) +
  coord_flip()

# malebias_Fig2_alltraits     #(panel A in Figure 4 in ms)

Prepare data for traits with CI not overlapping 0

create column with 1= different from zero, 0= zero included in CI


meta.plot2.sig <- meta_clean %>%
  mutate(
    lnCVRsig = ifelse(lnCVR_lower * lnCVR_upper > 0, 1, 0), lnVRsig = ifelse(lnVR_lower * lnVR_upper > 0, 1, 0),
    lnRRsig = ifelse(lnRR_lower * lnRR_upper > 0, 1, 0)
  )

meta.plot2.sig.b <- meta.plot2.sig[, c("lnCVR", "lnRR", "lnCVRsig", "lnVRsig", "lnRRsig", "GroupingTerm")] # "lnVR",

meta.plot2.sig.c <- gather(meta.plot2.sig.b, trait, value, lnCVR:lnRR)
meta.plot2.sig.c$sig <- "placeholder"

meta.plot2.sig.c$trait <- factor(meta.plot2.sig.c$trait, levels = c("lnCVR", "lnRR")) # "lnVR",

meta.plot2.sig.c$sig <- ifelse(meta.plot2.sig.c$trait == "lnCVR", meta.plot2.sig.c$lnCVRsig,
  ifelse(meta.plot2.sig.c$trait == "lnVR", meta.plot2.sig.c$lnVRsig, meta.plot2.sig.c$lnRRsig)
)

# choosing sex biased ln-ratios significantly larger than 0
meta.plot2.sig.malebias <- meta.plot2.sig.c %>%
  group_by_at(vars(trait, GroupingTerm)) %>%
  filter(sig == 1) %>%
  summarise(male_sig = sum(value > 0), female_sig = sum(value < 0), total = male_sig + female_sig)

meta.plot2.sig.malebias <- ungroup(meta.plot2.sig.malebias) %>%
  add_row(trait = "lnCVR", GroupingTerm = "Hearing", male_sig = 0, female_sig = 0, .before = 4) %>% # add "Hearing" for lnCVR (not filtered as only zeros)
  mutate(malepercent = male_sig * 100 / total, femalepercent = female_sig * 100 / total)

meta.plot2.sig.malebias$label <- "CI not overlapping zero"

# restructure to create stacked bar plots

meta.plot2.sig.bothsexes <- as.data.frame(meta.plot2.sig.malebias)
meta.plot2.sig.bothsexes.b <- gather(meta.plot2.sig.bothsexes, key = sex, value = percent, malepercent:femalepercent, factor_key = TRUE)

# create new sample size variable

meta.plot2.sig.bothsexes.b$samplesize <- with(meta.plot2.sig.bothsexes.b, ifelse(sex == "malepercent", male_sig, female_sig))

# *Plot Fig2 all significant results (CI not overlapping zero):
#     no sig. lnCVR for 'Hearing' in either sex; no sig. male-biased lnCVR for 'Immunology' and 'Eye, and no sig. male-biased lnVR for 'Eye'


malebias_Fig2_sigtraits <-
  ggplot(meta.plot2.sig.bothsexes.b) +
  aes(x = GroupingTerm, y = percent, fill = sex) +
  geom_col() +
  geom_hline(yintercept = 50, linetype = "dashed", color = "gray40") +
  geom_text(
    data = subset(meta.plot2.sig.bothsexes.b, samplesize != 0), aes(label = samplesize), position = position_stack(vjust = .5),
    color = "white", size = 3.5
  ) +
  facet_grid(
    cols = vars(trait), rows = vars(label), labeller = label_wrap_gen(width = 18),
    scales = "free", space = "free"
  ) +
  scale_fill_brewer(palette = "Set2") +
  theme_bw(base_size = 18) +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.position = "none",
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  ) +
  coord_flip()

Prepare data for traits with effect size ratios > 10% larger in males

meta.plot2.over10 <- meta_clean %>%
  select(lnCVR, lnRR, GroupingTerm) %>%
  arrange(GroupingTerm) # lnVR,

meta.plot2.over10.b <- gather(meta.plot2.over10, trait, value, c(lnCVR, lnRR)) # lnVR,

meta.plot2.over10.b$trait <- factor(meta.plot2.over10.b$trait, levels = c("lnCVR", "lnRR")) # "lnVR",

meta.plot2.over10.c <- meta.plot2.over10.b %>%
  group_by_at(vars(trait, GroupingTerm)) %>%
  summarise(
    malebias = sum(value > log(11 / 10)), femalebias = sum(value < log(9 / 10)), total = malebias + femalebias,
    malepercent = malebias * 100 / total, femalepercent = femalebias * 100 / total
  )

meta.plot2.over10.c$label <- "Sex difference in m/f ratios > 10%"

# restructure to create stacked bar plots

meta.plot2.over10.c <- as.data.frame(meta.plot2.over10.c)
meta.plot2.over10.d <- gather(meta.plot2.over10.c, key = sex, value = percent, malepercent:femalepercent, factor_key = TRUE)

# create new sample size variable

meta.plot2.over10.d$samplesize <- with(meta.plot2.over10.d, ifelse(sex == "malepercent", malebias, femalebias))

# *Plot Fig2 Sex difference in m/f ratio > 10%
malebias_Fig2_over10 <-
  ggplot(meta.plot2.over10.d) +
  aes(x = GroupingTerm, y = percent, fill = sex) +
  geom_col() +
  geom_hline(yintercept = 50, linetype = "dashed", color = "gray40") +
  geom_text(
    data = subset(meta.plot2.over10.d, samplesize != 0), aes(label = samplesize), position = position_stack(vjust = .5),
    color = "white", size = 3.5
  ) +
  facet_grid(
    cols = vars(trait), rows = vars(label), labeller = label_wrap_gen(width = 18),
    scales = "free", space = "free"
  ) +
  scale_fill_brewer(palette = "Set2") +
  theme_bw(base_size = 18) +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_blank(),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.position = "none",
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  ) +
  coord_flip()

# malebias_Fig2_over10  (Panel C in Fig 5 in ms)

Overall results of second order meta analysis (Figure 4: overall, Figure 5: sex-bias)

Restructure data for plotting

Data are restructured, and grouping terms are being re-ordered

overall3 <- gather(overall2, parameter, value, c(lnCVR, lnRR), factor_key = TRUE) # lnVR,

lnCVR.ci <- overall3 %>%
  filter(parameter == "lnCVR") %>%
  mutate(ci.low = lnCVR_lower, ci.high = lnCVR_upper)
lnVR.ci <- overall3 %>%
  filter(parameter == "lnVR") %>%
  mutate(ci.low = lnVR_lower, ci.high = lnVR_upper)
lnRR.ci <- overall3 %>%
  filter(parameter == "lnRR") %>%
  mutate(ci.low = lnRR_lower, ci.high = lnRR_upper)

overall4 <- bind_rows(lnCVR.ci, lnRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high) # lnVR.ci,

# re-order Grouping Terms

overall4$GroupingTerm <- factor(overall4$GroupingTerm, levels = c("Behaviour", "Morphology", "Metabolism", "Physiology", "Immunology", "Hematology", "Heart", "Hearing", "Eye", "All"))
overall4$GroupingTerm <- factor(overall4$GroupingTerm, rev(levels(overall4$GroupingTerm)))
overall4$label <- "All traits"

kable(cbind(overall4, overall4)) %>%
  kable_styling() %>%
  scroll_box(width = "100%", height = "200px")

Preparation for Plots FIGURE 4B & 5B, 5D (Second-order meta analysis results)

Preparation: Sub-Plot for Figure 3: all traits (4B)


Metameta_Fig3_alltraits <- overall4 %>%

  ggplot(aes(y = GroupingTerm, x = value)) +
  geom_errorbarh(aes(
    xmin = ci.low,
    xmax = ci.high
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(shape = parameter),
    fill = "black",
    color = "black", size = 2.2,
    show.legend = FALSE
  ) +
  scale_x_continuous(
    limits = c(-0.24, 0.25),
    breaks = c(-0.2, -0.1, 0, 0.1, 0.2),
    name = "Effect size"
  ) +
  geom_vline(
    xintercept = 0,
    color = "black",
    linetype = "dashed"
  ) +
  facet_grid(
    cols = vars(parameter), rows = vars(label),
    labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_text(hjust = 0.5, size = 14),
    axis.title.y = element_blank()
  )

# Metameta_Fig3_alltraits

Figure 5 - traits with CI not overlapping 0

Prepare data create column with 1= different from zero, 0= zero included in CI Male-biased (significant) traits

meta.male.plot3.sig <- metacombo %>%
  mutate(
    sigCVR = ifelse(lnCVR_lower > 0, 1, 0),
    sigVR = ifelse(lnVR_lower > 0, 1, 0),
    sigRR = ifelse(lnRR_lower > 0, 1, 0)
  )

# Significant subset for lnCVR
metacombo_male.plot3.CVR <- meta.male.plot3.sig %>%
  filter(sigCVR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_male.plot3.CVR.all <- meta.male.plot3.sig %>%
  filter(sigCVR == 1) %>%
  nest()

# Significant subset for lnVR
metacombo_male.plot3.VR <- meta.male.plot3.sig %>%
  filter(sigVR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_male.plot3.VR.all <- meta.male.plot3.sig %>%
  filter(sigVR == 1) %>%
  nest()

# Significant subset for lnRR
metacombo_male.plot3.RR <- meta.male.plot3.sig %>%
  filter(sigRR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_male.plot3.RR.all <- meta.male.plot3.sig %>%
  filter(sigRR == 1) %>%
  nest()

# **Final fixed effects meta-analyses within grouping terms, with SE of the estimate

plot3.male.meta.CVR <- metacombo_male.plot3.CVR %>%
  mutate(model_lnCVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnCVR, sei = (.x$lnCVR_upper - .x$lnCVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.male.meta.VR <- metacombo_male.plot3.VR %>%
  mutate(model_lnVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnVR, sei = (.x$lnVR_upper - .x$lnVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.male.meta.RR <- metacombo_male.plot3.RR %>%
  mutate(model_lnRR = map(data, ~ metafor::rma.uni(
    yi = .x$lnRR, sei = (.x$lnRR_upper - .x$lnRR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

# Across all grouping terms #

plot3.male.meta.CVR.all <- metacombo_male.plot3.CVR.all %>%
  mutate(model_lnCVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnCVR, sei = (.x$lnCVR_upper - .x$lnCVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.male.meta.CVR.all <- plot3.male.meta.CVR.all %>% mutate(GroupingTerm = "All")

plot3.male.meta.VR.all <- metacombo_male.plot3.VR.all %>%
  mutate(model_lnVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnVR, sei = (.x$lnVR_upper - .x$lnVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.male.meta.VR.all <- plot3.male.meta.VR.all %>% mutate(GroupingTerm = "All")

plot3.male.meta.RR.all <- metacombo_male.plot3.RR.all %>%
  mutate(model_lnRR = map(data, ~ metafor::rma.uni(
    yi = .x$lnRR, sei = (.x$lnRR_upper - .x$lnRR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.male.meta.RR.all <- plot3.male.meta.RR.all %>% mutate(GroupingTerm = "All")

# Combine with separate grouping term results

plot3.male.meta.CVR <- bind_rows(plot3.male.meta.CVR, plot3.male.meta.CVR.all)
plot3.male.meta.VR <- bind_rows(plot3.male.meta.VR, plot3.male.meta.VR.all)
plot3.male.meta.RR <- bind_rows(plot3.male.meta.RR, plot3.male.meta.RR.all)

# **Re-structure data for each grouping term; delete un-used variables

plot3.male.meta.CVR.b <- as.data.frame(plot3.male.meta.CVR %>% group_by(GroupingTerm) %>%
  mutate(
    lnCVR = map_dbl(model_lnCVR, pluck(2)), lnCVR_lower = map_dbl(model_lnCVR, pluck(6)),
    lnCVR_upper = map_dbl(model_lnCVR, pluck(7)), lnCVR_se = map_dbl(model_lnCVR, pluck(3))
  ))[, c(1, 4:7)]
add.row.hearing <- as.data.frame(t(c("Hearing", NA, NA, NA, NA))) %>% setNames(names(plot3.male.meta.CVR.b))

plot3.male.meta.CVR.b <- bind_rows(plot3.male.meta.CVR.b, add.row.hearing)
plot3.male.meta.CVR.b <- plot3.male.meta.CVR.b[order(plot3.male.meta.CVR.b$GroupingTerm), ]

plot3.male.meta.VR.b <- as.data.frame(plot3.male.meta.VR %>% group_by(GroupingTerm) %>%
  mutate(
    lnVR = map_dbl(model_lnVR, pluck(2)), lnVR_lower = map_dbl(model_lnVR, pluck(6)),
    lnVR_upper = map_dbl(model_lnVR, pluck(7)), lnVR_se = map_dbl(model_lnVR, pluck(3))
  ))[, c(1, 4:7)]
plot3.male.meta.VR.b <- plot3.male.meta.VR.b[order(plot3.male.meta.VR.b$GroupingTerm), ]

plot3.male.meta.RR.b <- as.data.frame(plot3.male.meta.RR %>% group_by(GroupingTerm) %>%
  mutate(
    lnRR = map_dbl(model_lnRR, pluck(2)), lnRR_lower = map_dbl(model_lnRR, pluck(6)),
    lnRR_upper = map_dbl(model_lnRR, pluck(7)), lnRR_se = map_dbl(model_lnRR, pluck(3))
  ))[, c(1, 4:7)]
plot3.male.meta.RR.b <- plot3.male.meta.RR.b[order(plot3.male.meta.RR.b$GroupingTerm), ]

overall.male.plot3 <- full_join(plot3.male.meta.CVR.b, plot3.male.meta.VR.b)
overall.male.plot3 <- full_join(overall.male.plot3, plot3.male.meta.RR.b)

overall.male.plot3$GroupingTerm <- factor(overall.male.plot3$GroupingTerm, levels = c("Behaviour", "Morphology", "Metabolism", "Physiology", "Immunology", "Hematology", "Heart", "Hearing", "Eye", "All"))
overall.male.plot3$GroupingTerm <- factor(overall.male.plot3$GroupingTerm, rev(levels(overall.male.plot3$GroupingTerm)))

# add missing GroupingTerms for plot
overall.male.plot3 <- add_row(overall.male.plot3, GroupingTerm = "Behaviour")
overall.male.plot3 <- add_row(overall.male.plot3, GroupingTerm = "Immunology")
overall.male.plot3 <- add_row(overall.male.plot3, GroupingTerm = "Eye")

overall.male.plot3$GroupingTerm <- factor(overall.male.plot3$GroupingTerm, levels = c("Behaviour", "Morphology", "Metabolism", "Physiology", "Immunology", "Hematology", "Heart", "Hearing", "Eye", "All"))
overall.male.plot3$GroupingTerm <- factor(overall.male.plot3$GroupingTerm, rev(levels(overall.male.plot3$GroupingTerm)))

# str(overall.male.plot3)

Restructure MALE data for plotting

overall3.male.sig <- gather(overall.male.plot3, parameter, value, c(lnCVR, lnRR), factor_key = TRUE) # lnVR,

lnCVR.ci <- overall3.male.sig %>%
  filter(parameter == "lnCVR") %>%
  mutate(ci.low = lnCVR_lower, ci.high = lnCVR_upper)
# lnVR.ci <- overall3.male.sig  %>% filter(parameter == "lnVR") %>% mutate(ci.low = lnVR_lower, ci.high = lnVR_upper)
lnRR.ci <- overall3.male.sig %>%
  filter(parameter == "lnRR") %>%
  mutate(ci.low = lnRR_lower, ci.high = lnRR_upper)

overall4.male.sig <- bind_rows(lnCVR.ci, lnRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high) # lnVR.ci,

overall4.male.sig$label <- "CI not overlapping zero"

Plot Fig5b all significant results (CI not overlapping zero) for males


Metameta_Fig3_male.sig <- overall4.male.sig %>%
  ggplot(aes(y = GroupingTerm, x = value)) +
  geom_errorbarh(aes(
    xmin = ci.low,
    xmax = ci.high
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(shape = parameter),
    fill = "mediumaquamarine", color = "mediumaquamarine", size = 2.2,
    show.legend = FALSE
  ) +
  scale_x_continuous(
    limits = c(0, 0.4),
    breaks = c(0, 0.3),
    name = "Effect size"
  ) +
  geom_vline(
    xintercept = 0,
    color = "black",
    linetype = "dashed"
  ) +
  facet_grid(
    cols = vars(parameter), rows = vars(label),
    labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  )

# Metameta_Fig3_male.sig

Female Figure, significant traits

Female Fig5B sig

Prepare data for traits with CI not overlapping 0 create column with 1= different from zero, 0= zero included in CI


# female-biased traits

meta.female.plot3.sig <- metacombo %>%
  mutate(
    sigCVR = ifelse(lnCVR_upper < 0, 1, 0),
    sigVR = ifelse(lnVR_upper < 0, 1, 0),
    sigRR = ifelse(lnRR_upper < 0, 1, 0)
  )

# Significant subset for lnCVR

metacombo_female.plot3.CVR <- meta.female.plot3.sig %>%
  filter(sigCVR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_female.plot3.CVR.all <- meta.female.plot3.sig %>%
  filter(sigCVR == 1) %>%
  nest()

# Significant subset for lnVR

metacombo_female.plot3.VR <- meta.female.plot3.sig %>%
  filter(sigVR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_female.plot3.VR.all <- meta.female.plot3.sig %>%
  filter(sigVR == 1) %>%
  nest()

# Significant subset for lnRR

metacombo_female.plot3.RR <- meta.female.plot3.sig %>%
  filter(sigRR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_female.plot3.RR.all <- meta.female.plot3.sig %>%
  filter(sigRR == 1) %>%
  nest()

# **Final fixed effects meta-analyses within grouping terms, with SE of the estimate

plot3.female.meta.CVR <- metacombo_female.plot3.CVR %>%
  mutate(model_lnCVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnCVR, sei = (.x$lnCVR_upper - .x$lnCVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.female.meta.VR <- metacombo_female.plot3.VR %>%
  mutate(model_lnVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnVR, sei = (.x$lnVR_upper - .x$lnVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.female.meta.RR <- metacombo_female.plot3.RR %>%
  mutate(model_lnRR = map(data, ~ metafor::rma.uni(
    yi = .x$lnRR, sei = (.x$lnRR_upper - .x$lnRR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

# Across all grouping terms #

plot3.female.meta.CVR.all <- metacombo_female.plot3.CVR.all %>%
  mutate(model_lnCVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnCVR, sei = (.x$lnCVR_upper - .x$lnCVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.female.meta.CVR.all <- plot3.female.meta.CVR.all %>% mutate(GroupingTerm = "All")

plot3.female.meta.VR.all <- metacombo_female.plot3.VR.all %>%
  mutate(model_lnVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnVR, sei = (.x$lnVR_upper - .x$lnVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.female.meta.VR.all <- plot3.female.meta.VR.all %>% mutate(GroupingTerm = "All")

plot3.female.meta.RR.all <- metacombo_female.plot3.RR.all %>%
  mutate(model_lnRR = map(data, ~ metafor::rma.uni(
    yi = .x$lnRR, sei = (.x$lnRR_upper - .x$lnRR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.female.meta.RR.all <- plot3.female.meta.RR.all %>% mutate(GroupingTerm = "All")

# Combine with separate grouping term results

plot3.female.meta.CVR <- bind_rows(plot3.female.meta.CVR, plot3.female.meta.CVR.all)
plot3.female.meta.VR <- bind_rows(plot3.female.meta.VR, plot3.female.meta.VR.all)
plot3.female.meta.RR <- bind_rows(plot3.female.meta.RR, plot3.female.meta.RR.all)

# **Re-structure data for each grouping term; delete un-used variables

plot3.female.meta.CVR.b <- as.data.frame(plot3.female.meta.CVR %>% group_by(GroupingTerm) %>%
  mutate(
    lnCVR = map_dbl(model_lnCVR, pluck(2)), lnCVR_lower = map_dbl(model_lnCVR, pluck(6)),
    lnCVR_upper = map_dbl(model_lnCVR, pluck(7)), lnCVR_se = map_dbl(model_lnCVR, pluck(3))
  ))[, c(1, 4:7)]

add.row.hearing <- as.data.frame(t(c("Hearing", NA, NA, NA, NA))) %>% setNames(names(plot3.female.meta.CVR.b))

plot3.female.meta.CVR.b <- bind_rows(plot3.female.meta.CVR.b, add.row.hearing)
plot3.female.meta.CVR.b <- plot3.female.meta.CVR.b[order(plot3.female.meta.CVR.b$GroupingTerm), ]

plot3.female.meta.VR.b <- as.data.frame(plot3.female.meta.VR %>% group_by(GroupingTerm) %>%
  mutate(
    lnVR = map_dbl(model_lnVR, pluck(2)), lnVR_lower = map_dbl(model_lnVR, pluck(6)),
    lnVR_upper = map_dbl(model_lnVR, pluck(7)), lnVR_se = map_dbl(model_lnVR, pluck(3))
  ))[, c(1, 4:7)]

plot3.female.meta.VR.b <- plot3.female.meta.VR.b[order(plot3.female.meta.VR.b$GroupingTerm), ]

plot3.female.meta.RR.b <- as.data.frame(plot3.female.meta.RR %>% group_by(GroupingTerm) %>%
  mutate(
    lnRR = map_dbl(model_lnRR, pluck(2)), lnRR_lower = map_dbl(model_lnRR, pluck(6)),
    lnRR_upper = map_dbl(model_lnRR, pluck(7)), lnRR_se = map_dbl(model_lnRR, pluck(3))
  ))[, c(1, 4:7)]

plot3.female.meta.RR.b <- plot3.female.meta.RR.b[order(plot3.female.meta.RR.b$GroupingTerm), ]

overall.female.plot3 <- full_join(plot3.female.meta.CVR.b, plot3.female.meta.VR.b)
overall.female.plot3 <- full_join(overall.female.plot3, plot3.female.meta.RR.b)

overall.female.plot3$GroupingTerm <- factor(overall.female.plot3$GroupingTerm, levels = c("Behaviour", "Morphology", "Metabolism", "Physiology", "Immunology", "Hematology", "Heart", "Hearing", "Eye", "All"))
overall.female.plot3$GroupingTerm <- factor(overall.female.plot3$GroupingTerm, rev(levels(overall.female.plot3$GroupingTerm)))

Restructure data for plotting

overall3.female.sig <- gather(overall.female.plot3, parameter, value, c(lnCVR, lnRR), factor_key = TRUE) # lnVR,

lnCVR.ci <- overall3.female.sig %>%
  filter(parameter == "lnCVR") %>%
  mutate(ci.low = lnCVR_lower, ci.high = lnCVR_upper)
# lnVR.ci <- overall3.female.sig  %>% filter(parameter == "lnVR") %>% mutate(ci.low = lnVR_lower, ci.high = lnVR_upper)
lnRR.ci <- overall3.female.sig %>%
  filter(parameter == "lnRR") %>%
  mutate(ci.low = lnRR_lower, ci.high = lnRR_upper)

overall4.female.sig <- bind_rows(lnCVR.ci, lnRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high) # lnVR.ci,

overall4.female.sig$label <- "CI not overlapping zero"

Plot Fig5B all significant results (CI not overlapping zero, female )


Metameta_Fig3_female.sig <- overall4.female.sig %>%
  ggplot(aes(y = GroupingTerm, x = value)) +
  geom_errorbarh(aes(
    xmin = ci.low,
    xmax = ci.high
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(shape = parameter),
    fill = "salmon1", color = "salmon1", size = 2.2,
    show.legend = FALSE
  ) +
  scale_x_continuous(
    limits = c(-0.4, 0),
    breaks = c(-0.3, 0),
    name = "Effect size"
  ) +
  geom_vline(
    xintercept = 0,
    color = "black",
    linetype = "dashed"
  ) +
  facet_grid(
    cols = vars(parameter), # rows = vars(label),
    # labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  )

# Metameta_Fig3_female.sig (Figure 5B left panel)

Fig5 D >10%

Prepare data for traits with m/f difference > 10%

create column with 1= larger, 0= diff not larger than 10%

Male Fig 5D > 10% (male biased traits)

meta.male.plot3.perc <- metacombo %>%
  mutate(
    percCVR = ifelse(lnCVR > log(11 / 10), 1, 0),
    percVR = ifelse(lnVR > log(11 / 10), 1, 0),
    percRR = ifelse(lnRR > log(11 / 10), 1, 0)
  )

# Significant subset for lnCVR
metacombo_male.plot3.CVR.perc <- meta.male.plot3.perc %>%
  filter(percCVR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_male.plot3.CVR.perc.all <- meta.male.plot3.perc %>%
  filter(percCVR == 1) %>%
  nest()

# Significant subset for lnVR
metacombo_male.plot3.VR.perc <- meta.male.plot3.perc %>%
  filter(percVR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_male.plot3.VR.perc.all <- meta.male.plot3.perc %>%
  filter(percVR == 1) %>%
  nest()

# Significant subset for lnRR
metacombo_male.plot3.RR.perc <- meta.male.plot3.perc %>%
  filter(percRR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_male.plot3.RR.perc.all <- meta.male.plot3.perc %>%
  filter(percRR == 1) %>%
  nest()


# **Final fixed effects meta-analyses within grouping terms and across grouping terms, with SE of the estimate

plot3.male.meta.CVR.perc <- metacombo_male.plot3.CVR.perc %>%
  mutate(model_lnCVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnCVR, sei = (.x$lnCVR_upper - .x$lnCVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.male.meta.VR.perc <- metacombo_male.plot3.VR.perc %>%
  mutate(model_lnVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnVR, sei = (.x$lnVR_upper - .x$lnVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.male.meta.RR.perc <- metacombo_male.plot3.RR.perc %>%
  mutate(model_lnRR = map(data, ~ metafor::rma.uni(
    yi = .x$lnRR, sei = (.x$lnRR_upper - .x$lnRR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

# Across all grouping terms #

plot3.male.meta.CVR.perc.all <- metacombo_male.plot3.CVR.perc.all %>%
  mutate(model_lnCVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnCVR, sei = (.x$lnCVR_upper - .x$lnCVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.male.meta.CVR.perc.all <- plot3.male.meta.CVR.perc.all %>% mutate(GroupingTerm = "All")

plot3.male.meta.VR.perc.all <- metacombo_male.plot3.VR.perc.all %>%
  mutate(model_lnVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnVR, sei = (.x$lnVR_upper - .x$lnVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.male.meta.VR.perc.all <- plot3.male.meta.VR.perc.all %>% mutate(GroupingTerm = "All")

plot3.male.meta.RR.perc.all <- metacombo_male.plot3.RR.perc.all %>%
  mutate(model_lnRR = map(data, ~ metafor::rma.uni(
    yi = .x$lnRR, sei = (.x$lnRR_upper - .x$lnRR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.male.meta.RR.perc.all <- plot3.male.meta.RR.perc.all %>% mutate(GroupingTerm = "All")

# Combine with separate grouping term results

plot3.male.meta.CVR.perc <- bind_rows(plot3.male.meta.CVR.perc, plot3.male.meta.CVR.perc.all)
plot3.male.meta.VR.perc <- bind_rows(plot3.male.meta.VR.perc, plot3.male.meta.VR.perc.all)
plot3.male.meta.RR.perc <- bind_rows(plot3.male.meta.RR.perc, plot3.male.meta.RR.perc.all)


# **Re-structure data for each grouping term; delete un-used variables: "Hearing missing for all 3 parameters"

plot3.male.meta.CVR.perc.b <- as.data.frame(plot3.male.meta.CVR.perc %>% group_by(GroupingTerm) %>%
  mutate(
    lnCVR = map_dbl(model_lnCVR, pluck(2)), lnCVR_lower = map_dbl(model_lnCVR, pluck(6)),
    lnCVR_upper = map_dbl(model_lnCVR, pluck(7)), lnCVR_se = map_dbl(model_lnCVR, pluck(3))
  ))[, c(1, 4:7)]
add.row.hearing <- as.data.frame(t(c("Hearing", NA, NA, NA, NA))) %>% setNames(names(plot3.male.meta.CVR.perc.b))
plot3.male.meta.CVR.perc.b <- rbind(plot3.male.meta.CVR.perc.b, add.row.hearing)
plot3.male.meta.CVR.perc.b <- plot3.male.meta.CVR.perc.b[order(plot3.male.meta.CVR.perc.b$GroupingTerm), ]

plot3.male.meta.VR.perc.b <- as.data.frame(plot3.male.meta.VR.perc %>% group_by(GroupingTerm) %>%
  mutate(
    lnVR = map_dbl(model_lnVR, pluck(2)), lnVR_lower = map_dbl(model_lnVR, pluck(6)),
    lnVR_upper = map_dbl(model_lnVR, pluck(7)), lnVR_se = map_dbl(model_lnVR, pluck(3))
  ))[, c(1, 4:7)]
add.row.hearing <- as.data.frame(t(c("Hearing", NA, NA, NA, NA))) %>% setNames(names(plot3.male.meta.VR.perc.b))
plot3.male.meta.VR.perc.b <- rbind(plot3.male.meta.VR.perc.b, add.row.hearing)
plot3.male.meta.VR.perc.b <- plot3.male.meta.VR.perc.b[order(plot3.male.meta.VR.perc.b$GroupingTerm), ]

plot3.male.meta.RR.perc.b <- as.data.frame(plot3.male.meta.RR.perc %>% group_by(GroupingTerm) %>%
  mutate(
    lnRR = map_dbl(model_lnRR, pluck(2)), lnRR_lower = map_dbl(model_lnRR, pluck(6)),
    lnRR_upper = map_dbl(model_lnRR, pluck(7)), lnRR_se = map_dbl(model_lnRR, pluck(3))
  ))[, c(1, 4:7)]
add.row.hearing <- as.data.frame(t(c("Hearing", NA, NA, NA, NA))) %>%
  setNames(names(plot3.male.meta.RR.perc.b))
plot3.male.meta.RR.perc.b <- rbind(plot3.male.meta.RR.perc.b, add.row.hearing)

add.row.eye <- as.data.frame(t(c("Eye", NA, NA, NA, NA))) %>%
  setNames(names(plot3.male.meta.RR.perc.b))
plot3.male.meta.RR.perc.b <- rbind(plot3.male.meta.RR.perc.b, add.row.eye)

plot3.male.meta.RR.perc.b <- plot3.male.meta.RR.perc.b[order(plot3.male.meta.RR.perc.b$GroupingTerm), ]

plot3.male.meta.CVR.Vr.perc <- full_join(plot3.male.meta.CVR.perc.b, plot3.male.meta.VR.perc.b)
overall.male.plot3.perc <- full_join(plot3.male.meta.CVR.Vr.perc, plot3.male.meta.RR.perc.b)


overall.male.plot3.perc$GroupingTerm <- factor(overall.male.plot3.perc$GroupingTerm, levels = c("Behaviour", "Morphology", "Metabolism", "Physiology", "Immunology", "Hematology", "Heart", "Hearing", "Eye", "All"))
overall.male.plot3.perc$GroupingTerm <- factor(overall.male.plot3.perc$GroupingTerm, rev(levels(overall.male.plot3.perc$GroupingTerm)))

Restructure data for plotting : Male biased, 10% difference

overall3.perc <- gather(overall.male.plot3.perc, parameter, value, c(lnCVR, lnRR), factor_key = TRUE) # lnVR,

lnCVR.ci <- overall3.perc %>%
  filter(parameter == "lnCVR") %>%
  mutate(ci.low = lnCVR_lower, ci.high = lnCVR_upper)
# lnVR.ci <- overall3.perc  %>% filter(parameter == "lnVR") %>% mutate(ci.low = lnVR_lower, ci.high = lnVR_upper)
lnRR.ci <- overall3.perc %>%
  filter(parameter == "lnRR") %>%
  mutate(ci.low = lnRR_lower, ci.high = lnRR_upper)

overall4.male.perc <- bind_rows(lnCVR.ci, lnRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high) # lnVR.ci,

overall4.male.perc$label <- "Sex difference in m/f ratios > 10%"

overall4.male.perc$value <- as.numeric(overall4.male.perc$value)
overall4.male.perc$ci.low <- as.numeric(overall4.male.perc$ci.low)
overall4.male.perc$ci.high <- as.numeric(overall4.male.perc$ci.high)

Plot Fig5D all >10% difference (male bias)


Metameta_Fig3_male.perc <- overall4.male.perc %>% # filter(., GroupingTerm != "Hearing") %>%
  ggplot(aes(y = GroupingTerm, x = value)) +
  geom_errorbarh(aes(
    xmin = ci.low,
    xmax = ci.high
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(
    shape = parameter,
    fill = parameter
  ),
  color = "mediumaquamarine", size = 2.2,
  show.legend = FALSE
  ) +
  scale_x_continuous(
    limits = c(-0.2, 0.62),
    breaks = c(0, 0.3),
    name = "Effect size"
  ) +
  geom_vline(
    xintercept = 0,
    color = "black",
    linetype = "dashed"
  ) +
  facet_grid(
    cols = vars(parameter), rows = vars(label),
    labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_blank(),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_text(hjust = 0.5, size = 14),
    axis.title.y = element_blank()
  )

# Metameta_Fig3_male.perc (Figure 5D right panel)

Female Fig 5D >10%


meta.plot3.perc <- metacombo %>%
  mutate(
    percCVR = ifelse(lnCVR < log(9 / 10), 1, 0),
    percVR = ifelse(lnVR < log(9 / 10), 1, 0),
    percRR = ifelse(lnRR < log(9 / 10), 1, 0)
  )

# Significant subset for lnCVR
metacombo_plot3.CVR.perc <- meta.plot3.perc %>%
  filter(percCVR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_plot3.CVR.perc.all <- meta.plot3.perc %>%
  filter(percCVR == 1) %>%
  nest()

# Significant subset for lnVR
metacombo_plot3.VR.perc <- meta.plot3.perc %>%
  filter(percVR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_plot3.VR.perc.all <- meta.plot3.perc %>%
  filter(percVR == 1) %>%
  nest()

# Significant subset for lnRR
metacombo_plot3.RR.perc <- meta.plot3.perc %>%
  filter(percRR == 1) %>%
  group_by(GroupingTerm) %>%
  nest()

metacombo_plot3.RR.perc.all <- meta.plot3.perc %>%
  filter(percRR == 1) %>%
  nest()


# **Final fixed effects meta-analyses within grouping terms, with SE of the estimate

plot3.meta.CVR.perc <- metacombo_plot3.CVR.perc %>%
  mutate(model_lnCVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnCVR, sei = (.x$lnCVR_upper - .x$lnCVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.meta.VR.perc <- metacombo_plot3.VR.perc %>%
  mutate(model_lnVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnVR, sei = (.x$lnVR_upper - .x$lnVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.meta.RR.perc <- metacombo_plot3.RR.perc %>%
  mutate(model_lnRR = map(data, ~ metafor::rma.uni(
    yi = .x$lnRR, sei = (.x$lnRR_upper - .x$lnRR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

# Across all grouping terms #

plot3.meta.CVR.perc.all <- metacombo_plot3.CVR.perc.all %>%
  mutate(model_lnCVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnCVR, sei = (.x$lnCVR_upper - .x$lnCVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.meta.CVR.perc.all <- plot3.meta.CVR.perc.all %>% mutate(GroupingTerm = "All")

plot3.meta.VR.perc.all <- metacombo_plot3.VR.perc.all %>%
  mutate(model_lnVR = map(data, ~ metafor::rma.uni(
    yi = .x$lnVR, sei = (.x$lnVR_upper - .x$lnVR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.meta.VR.perc.all <- plot3.meta.VR.perc.all %>% mutate(GroupingTerm = "All")

plot3.meta.RR.perc.all <- metacombo_plot3.RR.perc.all %>%
  mutate(model_lnRR = map(data, ~ metafor::rma.uni(
    yi = .x$lnRR, sei = (.x$lnRR_upper - .x$lnRR_lower) / (2 * 1.96),
    control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), verbose = F
  )))

plot3.meta.RR.perc.all <- plot3.meta.RR.perc.all %>% mutate(GroupingTerm = "All")

# Combine with separate grouping term results

plot3.meta.CVR.perc <- bind_rows(plot3.meta.CVR.perc, plot3.meta.CVR.perc.all)
plot3.meta.VR.perc <- bind_rows(plot3.meta.VR.perc, plot3.meta.VR.perc.all)
plot3.meta.RR.perc <- bind_rows(plot3.meta.RR.perc, plot3.meta.RR.perc.all)


# **Re-structure data for each grouping term; delete un-used variables: "Hearing missing for all 3 parameters"

plot3.meta.CVR.perc.b <- as.data.frame(plot3.meta.CVR.perc %>% group_by(GroupingTerm) %>%
  mutate(
    lnCVR = map_dbl(model_lnCVR, pluck(2)), lnCVR_lower = map_dbl(model_lnCVR, pluck(6)),
    lnCVR_upper = map_dbl(model_lnCVR, pluck(7)), lnCVR_se = map_dbl(model_lnCVR, pluck(3))
  ))[, c(1, 4:7)]
add.row.hearing <- as.data.frame(t(c("Hearing", NA, NA, NA, NA))) %>% setNames(names(plot3.meta.CVR.perc.b))
plot3.meta.CVR.perc.b <- rbind(plot3.meta.CVR.perc.b, add.row.hearing)
plot3.meta.CVR.perc.b <- plot3.meta.CVR.perc.b[order(plot3.meta.CVR.perc.b$GroupingTerm), ]

plot3.meta.VR.perc.b <- as.data.frame(plot3.meta.VR.perc %>% group_by(GroupingTerm) %>%
  mutate(
    lnVR = map_dbl(model_lnVR, pluck(2)), lnVR_lower = map_dbl(model_lnVR, pluck(6)),
    lnVR_upper = map_dbl(model_lnVR, pluck(7)), lnVR_se = map_dbl(model_lnVR, pluck(3))
  ))[, c(1, 4:7)]
add.row.hearing <- as.data.frame(t(c("Hearing", NA, NA, NA, NA))) %>% setNames(names(plot3.meta.VR.perc.b))
plot3.meta.VR.perc.b <- rbind(plot3.meta.VR.perc.b, add.row.hearing)
plot3.meta.VR.perc.b <- plot3.meta.VR.perc.b[order(plot3.meta.VR.perc.b$GroupingTerm), ]

plot3.meta.RR.perc.b <- as.data.frame(plot3.meta.RR.perc %>% group_by(GroupingTerm) %>%
  mutate(
    lnRR = map_dbl(model_lnRR, pluck(2)), lnRR_lower = map_dbl(model_lnRR, pluck(6)),
    lnRR_upper = map_dbl(model_lnRR, pluck(7)), lnRR_se = map_dbl(model_lnRR, pluck(3))
  ))[, c(1, 4:7)]
add.row.hearing <- as.data.frame(t(c("Hearing", NA, NA, NA, NA))) %>% setNames(names(plot3.meta.RR.perc.b))
plot3.meta.RR.perc.b <- rbind(plot3.meta.RR.perc.b, add.row.hearing)
add.row.hematology <- as.data.frame(t(c("Hematology", NA, NA, NA, NA))) %>%
  setNames(names(plot3.meta.RR.perc.b))
plot3.meta.RR.perc.b <- rbind(plot3.meta.RR.perc.b, add.row.hematology)


plot3.meta.RR.perc.b <- plot3.meta.RR.perc.b[order(plot3.meta.RR.perc.b$GroupingTerm), ]

plot3.meta.CVR.perc.c <- full_join(plot3.meta.CVR.perc.b, plot3.meta.VR.perc.b)
overall.plot3.perc <- full_join(plot3.meta.CVR.perc.c, plot3.meta.RR.perc.b)


overall.plot3.perc$GroupingTerm <- factor(overall.plot3.perc$GroupingTerm, levels = c("Behaviour", "Morphology", "Metabolism", "Physiology", "Immunology", "Hematology", "Heart", "Hearing", "Eye", "All"))
overall.plot3.perc$GroupingTerm <- factor(overall.plot3.perc$GroupingTerm, rev(levels(overall.plot3.perc$GroupingTerm)))

Restructure data for plotting Female bias, 10 percent difference

overall3.perc <- gather(overall.plot3.perc, parameter, value, c(lnCVR, lnRR), factor_key = TRUE) # lnVR,

lnCVR.ci <- overall3.perc %>%
  filter(parameter == "lnCVR") %>%
  mutate(ci.low = lnCVR_lower, ci.high = lnCVR_upper)
# lnVR.ci <- overall3.perc  %>% filter(parameter == "lnVR") %>% mutate(ci.low = lnVR_lower, ci.high = lnVR_upper)
lnRR.ci <- overall3.perc %>%
  filter(parameter == "lnRR") %>%
  mutate(ci.low = lnRR_lower, ci.high = lnRR_upper)

overall4.perc <- bind_rows(lnCVR.ci, lnRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high) # lnVR.ci,

overall4.perc$label <- "Sex difference in m/f ratios > 10%"

overall4.perc$value <- as.numeric(overall4.perc$value)
overall4.perc$ci.low <- as.numeric(overall4.perc$ci.low)
overall4.perc$ci.high <- as.numeric(overall4.perc$ci.high)

Plot Fig5D all >10% difference (female)

Metameta_Fig3_female.perc <- overall4.perc %>%
  ggplot(aes(y = GroupingTerm, x = value)) +
  geom_errorbarh(aes(
    xmin = ci.low,
    xmax = ci.high
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(shape = parameter),
    fill = "salmon1", color = "salmon1", size = 2.2,
    show.legend = FALSE
  ) +

  # scale_shape_manual(values =

  scale_x_continuous(
    limits = c(-0.53, 0.2),
    breaks = c(-0.3, 0),
    name = "Effect size"
  ) +
  geom_vline(
    xintercept = 0,
    color = "black",
    linetype = "dashed"
  ) +
  facet_grid(
    cols = vars(parameter), # rows = vars(label),
    # labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_blank(),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_text(hjust = 0.5, size = 14),
    axis.title.y = element_blank()
  )

# Metameta_Fig3_female.perc (Figure 5D left panel)

Plot Fig5: plots combined

library(ggpubr)
Fig5b <- ggarrange(Metameta_Fig3_female.sig, Metameta_Fig3_male.sig,
  ncol = 2, nrow = 1, widths = c(1, 1.20), heights = c(1, 1)
)

Fig5d <- ggarrange(Metameta_Fig3_female.perc, Metameta_Fig3_male.perc,
  ncol = 2, nrow = 1, widths = c(1, 1.20), heights = c(1, 1)
)

# end combination Figure 5

Fig5 <- ggarrange(malebias_Fig2_sigtraits, malebias_Fig2_over10, Fig5b, Fig5d, ncol = 1, nrow = 4, heights = c(2.3, 2, 2.1, 2), labels = c("A", " ", "B", " "))
Fig5

Heterogeneity

FIGURE 4 (Second-order meta analysis on heterogeneity)

Create matrix to store results for all traits

results.allhetero.grouping <- as.data.frame(cbind(c(1:n), matrix(rep(0, n * 30), ncol = 30)))
names(results.allhetero.grouping) <- c(
  "id", "sigma2_strain.CVR", "sigma2_center.CVR", "sigma2_error.CVR", "s.nlevels.strain.CVR",
  "s.nlevels.center.CVR", "s.nlevels.error.CVR", "sigma2_strain.VR", "sigma2_center.VR", "sigma2_error.VR", "s.nlevels.strain.VR",
  "s.nlevels.center.VR", "s.nlevels.error.VR", "sigma2_strain.RR", "sigma2_center.RR", "sigma2_error.RR", "s.nlevels.strain.RR",
  "s.nlevels.center.RR", "s.nlevels.error.RR", "lnCVR", "lnCVR_lower", "lnCVR_upper", "lnCVR_se", "lnVR", "lnVR_lower", "lnVR_upper",
  "lnVR_se", "lnRR", "lnRR_lower", "lnRR_upper", "lnRR_se"
)

LOOP Parameters to extract from metafor (sigma2’s, s.nlevels)


for (t in 1:n) {
  tryCatch(
    {
      data_par_age <- data_subset_parameterid_individual_by_age(data, t, age_min = 0, age_center = 100)

      population_stats <- calculate_population_stats(data_par_age)

      results <- create_meta_analysis_effect_sizes(population_stats)

      # lnCVR, logaritm of the ratio of male and female coefficients of variance

      cvr. <- metafor::rma.mv(yi = effect_size_CVR, V = sample_variance_CVR, random = list(
        ~ 1 | strain_name, ~ 1 | production_center,
        ~ 1 | err
      ), control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), data = results)
      results.allhetero.grouping[t, 2] <- cvr.$sigma2[1]
      results.allhetero.grouping[t, 3] <- cvr.$sigma2[2]
      results.allhetero.grouping[t, 4] <- cvr.$sigma2[3]
      results.allhetero.grouping[t, 5] <- cvr.$s.nlevels[1]
      results.allhetero.grouping[t, 6] <- cvr.$s.nlevels[2]
      results.allhetero.grouping[t, 7] <- cvr.$s.nlevels[3]
      results.allhetero.grouping[t, 20] <- cvr.$b
      results.allhetero.grouping[t, 21] <- cvr.$ci.lb
      results.allhetero.grouping[t, 22] <- cvr.$ci.ub
      results.allhetero.grouping[t, 23] <- cvr.$se

      # lnVR, male to female variability ratio (logarithm of male and female standard deviations)

      vr. <- metafor::rma.mv(yi = effect_size_VR, V = sample_variance_VR, random = list(
        ~ 1 | strain_name, ~ 1 | production_center,
        ~ 1 | err
      ), control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), data = results)
      results.allhetero.grouping[t, 8] <- vr.$sigma2[1]
      results.allhetero.grouping[t, 9] <- vr.$sigma2[2]
      results.allhetero.grouping[t, 10] <- vr.$sigma2[3]
      results.allhetero.grouping[t, 11] <- vr.$s.nlevels[1]
      results.allhetero.grouping[t, 12] <- vr.$s.nlevels[2]
      results.allhetero.grouping[t, 13] <- vr.$s.nlevels[3]
      results.allhetero.grouping[t, 24] <- vr.$b
      results.allhetero.grouping[t, 25] <- vr.$ci.lb
      results.allhetero.grouping[t, 26] <- vr.$ci.ub
      results.allhetero.grouping[t, 27] <- vr.$se

      # lnRR, response ratio (logarithm of male and female means)

      rr. <- metafor::rma.mv(yi = effect_size_RR, V = sample_variance_RR, random = list(
        ~ 1 | strain_name, ~ 1 | production_center,
        ~ 1 | err
      ), control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 1000), data = results)
      results.allhetero.grouping[t, 14] <- rr.$sigma2[1]
      results.allhetero.grouping[t, 15] <- rr.$sigma2[2]
      results.allhetero.grouping[t, 16] <- rr.$sigma2[3]
      results.allhetero.grouping[t, 17] <- rr.$s.nlevels[1]
      results.allhetero.grouping[t, 18] <- rr.$s.nlevels[2]
      results.allhetero.grouping[t, 19] <- rr.$s.nlevels[3]
      results.allhetero.grouping[t, 28] <- rr.$b
      results.allhetero.grouping[t, 29] <- rr.$ci.lb
      results.allhetero.grouping[t, 30] <- rr.$ci.ub
      results.allhetero.grouping[t, 31] <- rr.$se
    },
    error = function(e) {
      cat("ERROR :", conditionMessage(e), "\n")
    }
  )
}

Exclude traits, merge datasets

results.allhetero.grouping2 <- results.allhetero.grouping[results.allhetero.grouping$s.nlevels.strain.VR != 0, ]
# nrow(results.allhetero.grouping2) #218

Merge data sets containing metafor results with procedure etc. names

# procedures <- read.csv(here("export", "procedures.csv"))

results.allhetero.grouping2$parameter_group <- data$parameter_group[match(results.allhetero.grouping2$id, data$id)]
results.allhetero.grouping2$procedure <- data$procedure_name[match(results.allhetero.grouping2$id, data$id)]

results.allhetero.grouping2$GroupingTerm <- procedures$GroupingTerm[match(results.allhetero.grouping2$procedure, procedures$procedure)]
results.allhetero.grouping2$parameter_name <- data$parameter_name[match(results.allhetero.grouping2$id, data$id)]

Correlated parameters

metahetero1 <- results.allhetero.grouping2
# length(unique(metahetero1$procedure)) #18
# length(unique(metahetero1$GroupingTerm)) #9
# length(unique(metahetero1$parameter_group)) # 149
# length(unique(metahetero1$parameter_name)) #218

# Count of number of parameter names (correlated sub-traits) in each parameter group (par_group_size)

metahetero1b <-
  metahetero1 %>%
  group_by(parameter_group) %>%
  mutate(par_group_size = n_distinct(parameter_name))

metahetero1$par_group_size <- metahetero1b$par_group_size[match(metahetero1$parameter_group, metahetero1b$parameter_group)]

# Create subsets with > 1 count (par_group_size > 1)

metahetero1_sub <- subset(metahetero1, par_group_size > 1) # 90 observations
# str(metahetero1_sub)
# metahetero1_sub$sampleSize <- as.numeric(metahetero1_sub$sampleSize) #from previous analysis? don't think is used: : delete in final version

# Nest data

n_count. <- metahetero1_sub %>%
  group_by(parameter_group) %>%
  # mutate(raw_N = sum(sampleSize)) %>%  #don't think is necessary: delete in final version
  nest()

# meta-analysis preparation

model_count. <- n_count. %>%
  mutate(
    model_lnRR = map(data, ~ robu(.x$lnRR ~ 1,
      data = .x, studynum = .x$id, modelweights = c("CORR"), rho = 0.8,
      small = TRUE, var.eff.size = (.x$lnRR_se)^2
    )),
    model_lnVR = map(data, ~ robu(.x$lnVR ~ 1,
      data = .x, studynum = .x$id, modelweights = c("CORR"), rho = 0.8,
      small = TRUE, var.eff.size = (.x$lnVR_se)^2
    )),
    model_lnCVR = map(data, ~ robu(.x$lnCVR ~ 1,
      data = .x, studynum = .x$id, modelweights = c("CORR"), rho = 0.8,
      small = TRUE, var.eff.size = (.x$lnCVR_se)^2
    ))
  )


# Robumeta object details:
# str(model_count.$model_lnCVR[[1]])

## *Perform meta-analyses on correlated sub-traits, using robumeta

# Shinichi: We think we want to use these for further analyses:
# residual variance: as.numeric(robu_fit$mod_info$term1)     (same as 'mod_info$tau.sq')
# sample size: robu_fit$N

## **Extract and save parameter estimates

count_fun. <- function(mod_sub) {
  return(c(as.numeric(mod_sub$mod_info$term1), mod_sub$N))
}

robusub_RR. <- model_count. %>%
  transmute(parameter_group, estimatelnRR = map(model_lnRR, count_fun.)) %>%
  mutate(r = map(estimatelnRR, ~ data.frame(t(.)))) %>%
  unnest(r) %>%
  select(-estimatelnRR) %>%
  purrr::set_names(c("parameter_group", "var.RR", "N.RR"))

robusub_CVR. <- model_count. %>%
  transmute(parameter_group, estimatelnCVR = map(model_lnCVR, count_fun.)) %>%
  mutate(r = map(estimatelnCVR, ~ data.frame(t(.)))) %>%
  unnest(r) %>%
  select(-estimatelnCVR) %>%
  purrr::set_names(c("parameter_group", "var.CVR", "N.CVR"))

robusub_VR. <- model_count. %>%
  transmute(parameter_group, estimatelnVR = map(model_lnVR, count_fun.)) %>%
  mutate(r = map(estimatelnVR, ~ data.frame(t(.)))) %>%
  unnest(r) %>%
  select(-estimatelnVR) %>%
  purrr::set_names(c("parameter_group", "var.VR", "N.VR"))

robu_all. <- full_join(robusub_CVR., robusub_VR.) %>% full_join(., robusub_RR.)

Merge the two data sets (the new [robu_all.] and the initial [uncorrelated sub-traits with count = 1])

In this step, we
1) merge the N from robumeta and the N from metafor (s.nlevels.error) together into the same columns (N.RR, N.VR, N.CVR) 2) calculate the total variance for metafor models as the sum of random effect variances and the residual error, then add in the same columns together with the residual variances from robumeta

metahetero_all <- metahetero1 %>%
  filter(par_group_size == 1) %>%
  as_tibble()
metahetero_all$N.RR <- metahetero_all$s.nlevels.error.RR
metahetero_all$N.CVR <- metahetero_all$s.nlevels.error.CVR
metahetero_all$N.VR <- metahetero_all$s.nlevels.error.VR
metahetero_all$var.RR <- log(sqrt(metahetero_all$sigma2_strain.RR + metahetero_all$sigma2_center.RR + metahetero_all$sigma2_error.RR))
metahetero_all$var.VR <- log(sqrt(metahetero_all$sigma2_strain.VR + metahetero_all$sigma2_center.VR + metahetero_all$sigma2_error.VR))
metahetero_all$var.CVR <- log(sqrt(metahetero_all$sigma2_strain.CVR + metahetero_all$sigma2_center.CVR + metahetero_all$sigma2_error.CVR))
# str(metahetero_all)
# str(robu_all.)

metahetero_all <- metahetero_all %>% mutate(
  var.RR = if_else(var.RR == -Inf, -7, var.RR),
  var.VR = if_else(var.VR == -Inf, -5, var.VR),
  var.CVR = if_else(var.CVR == -Inf, -6, var.CVR)
)

# **Combine data
## Step1
combinedmetahetero <- bind_rows(robu_all., metahetero_all)
# glimpse(combinedmetahetero)

# Steps 2&3

metacombohetero <- combinedmetahetero
metacombohetero$counts <- metahetero1$par_group_size[match(metacombohetero$parameter_group, metahetero1$parameter_group)]
metacombohetero$procedure2 <- metahetero1$procedure[match(metacombohetero$parameter_group, metahetero1$parameter_group)]
metacombohetero$GroupingTerm2 <- metahetero1$GroupingTerm[match(metacombohetero$parameter_group, metahetero1$parameter_group)]

# **Clean-up and rename

metacombohetero <- metacombohetero[, c(1:7, 43:45)]
names(metacombohetero)[9] <- "procedure"
names(metacombohetero)[10] <- "GroupingTerm"

Meta-analysis of heterogeneity

## *Perform meta-meta-analysis (3 for each of the 9 grouping terms: var.CVR, var.VR, var.RR)

metacombohetero_final <- metacombohetero %>%
  group_by(GroupingTerm) %>%
  nest()

# Final fixed effects meta-analyses within grouping terms, with SE of the estimate

# metacombohetero$var.CVR

heterog1 <- metacombohetero_final %>%

  mutate(
    model_heteroCVR = map(data, ~ metafor::rma.uni(
      yi = .x$var.CVR, sei = sqrt(1 / 2 * (.x$N.CVR - 1)),
      control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 10000, stepadj = 0.5), verbose = F
    )),
    model_heteroVR = map(data, ~ metafor::rma.uni(
      yi = .x$var.VR, sei = sqrt(1 / 2 * (.x$N.VR - 1)),
      control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 10000, stepadj = 0.5), verbose = F
    )),
    model_heteroRR = map(data, ~ metafor::rma.uni(
      yi = .x$var.RR, sei = sqrt(1 / 2 * (.x$N.RR - 1)),
      control = list(optimizer = "optim", optmethod = "Nelder-Mead", maxit = 10000, stepadj = 0.5), verbose = F
    ))
  )


# **Re-structure data for each grouping term; extract heterogenenity/variance terms; delete un-used variables

Behaviour. <- heterog1 %>%
  filter(., GroupingTerm == "Behaviour") %>%
  select(., -data) %>%
  mutate(
    heteroCVR = .[[2]][[1]]$b, heteroCVR_lower = .[[2]][[1]]$ci.lb, heteroCVR_upper = .[[2]][[1]]$ci.ub, heteroCVR_se = .[[2]][[1]]$se,
    heteroVR = .[[3]][[1]]$b, heteroVR_lower = .[[3]][[1]]$ci.lb, heteroVR_upper = .[[3]][[1]]$ci.ub, heteroVR_se = .[[3]][[1]]$se,
    heteroRR = .[[4]][[1]]$b, heteroRR_lower = .[[4]][[1]]$ci.lb, heteroRR_upper = .[[4]][[1]]$ci.ub, heteroRR_se = .[[4]][[1]]$se
  ) %>%
  select(., GroupingTerm, heteroCVR:heteroRR_se)

Immunology. <- heterog1 %>%
  filter(., GroupingTerm == "Immunology") %>%
  select(., -data) %>%
  mutate(
    heteroCVR = .[[2]][[1]]$b, heteroCVR_lower = .[[2]][[1]]$ci.lb, heteroCVR_upper = .[[2]][[1]]$ci.ub, heteroCVR_se = .[[2]][[1]]$se,
    heteroVR = .[[3]][[1]]$b, heteroVR_lower = .[[3]][[1]]$ci.lb, heteroVR_upper = .[[3]][[1]]$ci.ub, heteroVR_se = .[[3]][[1]]$se,
    heteroRR = .[[4]][[1]]$b, heteroRR_lower = .[[4]][[1]]$ci.lb, heteroRR_upper = .[[4]][[1]]$ci.ub, heteroRR_se = .[[4]][[1]]$se
  ) %>%
  select(., GroupingTerm, heteroCVR:heteroRR_se)


Hematology. <- heterog1 %>%
  filter(., GroupingTerm == "Hematology") %>%
  select(., -data) %>%
  mutate(
    heteroCVR = .[[2]][[1]]$b, heteroCVR_lower = .[[2]][[1]]$ci.lb, heteroCVR_upper = .[[2]][[1]]$ci.ub, heteroCVR_se = .[[2]][[1]]$se,
    heteroVR = .[[3]][[1]]$b, heteroVR_lower = .[[3]][[1]]$ci.lb, heteroVR_upper = .[[3]][[1]]$ci.ub, heteroVR_se = .[[3]][[1]]$se,
    heteroRR = .[[4]][[1]]$b, heteroRR_lower = .[[4]][[1]]$ci.lb, heteroRR_upper = .[[4]][[1]]$ci.ub, heteroRR_se = .[[4]][[1]]$se
  ) %>%
  select(., GroupingTerm, heteroCVR:heteroRR_se)


Hearing. <- heterog1 %>%
  filter(., GroupingTerm == "Hearing") %>%
  select(., -data) %>%
  mutate(
    heteroCVR = .[[2]][[1]]$b, heteroCVR_lower = .[[2]][[1]]$ci.lb, heteroCVR_upper = .[[2]][[1]]$ci.ub, heteroCVR_se = .[[2]][[1]]$se,
    heteroVR = .[[3]][[1]]$b, heteroVR_lower = .[[3]][[1]]$ci.lb, heteroVR_upper = .[[3]][[1]]$ci.ub, heteroVR_se = .[[3]][[1]]$se,
    heteroRR = .[[4]][[1]]$b, heteroRR_lower = .[[4]][[1]]$ci.lb, heteroRR_upper = .[[4]][[1]]$ci.ub, heteroRR_se = .[[4]][[1]]$se
  ) %>%
  select(., GroupingTerm, heteroCVR:heteroRR_se)

Physiology. <- heterog1 %>%
  filter(., GroupingTerm == "Physiology") %>%
  select(., -data) %>%
  mutate(
    heteroCVR = .[[2]][[1]]$b, heteroCVR_lower = .[[2]][[1]]$ci.lb, heteroCVR_upper = .[[2]][[1]]$ci.ub, heteroCVR_se = .[[2]][[1]]$se,
    heteroVR = .[[3]][[1]]$b, heteroVR_lower = .[[3]][[1]]$ci.lb, heteroVR_upper = .[[3]][[1]]$ci.ub, heteroVR_se = .[[3]][[1]]$se,
    heteroRR = .[[4]][[1]]$b, heteroRR_lower = .[[4]][[1]]$ci.lb, heteroRR_upper = .[[4]][[1]]$ci.ub, heteroRR_se = .[[4]][[1]]$se
  ) %>%
  select(., GroupingTerm, heteroCVR:heteroRR_se)

Metabolism. <- heterog1 %>%
  filter(., GroupingTerm == "Metabolism") %>%
  select(., -data) %>%
  mutate(
    heteroCVR = .[[2]][[1]]$b, heteroCVR_lower = .[[2]][[1]]$ci.lb, heteroCVR_upper = .[[2]][[1]]$ci.ub, heteroCVR_se = .[[2]][[1]]$se,
    heteroVR = .[[3]][[1]]$b, heteroVR_lower = .[[3]][[1]]$ci.lb, heteroVR_upper = .[[3]][[1]]$ci.ub, heteroVR_se = .[[3]][[1]]$se,
    heteroRR = .[[4]][[1]]$b, heteroRR_lower = .[[4]][[1]]$ci.lb, heteroRR_upper = .[[4]][[1]]$ci.ub, heteroRR_se = .[[4]][[1]]$se
  ) %>%
  select(., GroupingTerm, heteroCVR:heteroRR_se)

Morphology. <- heterog1 %>%
  filter(., GroupingTerm == "Morphology") %>%
  select(., -data) %>%
  mutate(
    heteroCVR = .[[2]][[1]]$b, heteroCVR_lower = .[[2]][[1]]$ci.lb, heteroCVR_upper = .[[2]][[1]]$ci.ub, heteroCVR_se = .[[2]][[1]]$se,
    heteroVR = .[[3]][[1]]$b, heteroVR_lower = .[[3]][[1]]$ci.lb, heteroVR_upper = .[[3]][[1]]$ci.ub, heteroVR_se = .[[3]][[1]]$se,
    heteroRR = .[[4]][[1]]$b, heteroRR_lower = .[[4]][[1]]$ci.lb, heteroRR_upper = .[[4]][[1]]$ci.ub, heteroRR_se = .[[4]][[1]]$se
  ) %>%
  select(., GroupingTerm, heteroCVR:heteroRR_se)

Heart. <- heterog1 %>%
  filter(., GroupingTerm == "Heart") %>%
  select(., -data) %>%
  mutate(
    heteroCVR = .[[2]][[1]]$b, heteroCVR_lower = .[[2]][[1]]$ci.lb, heteroCVR_upper = .[[2]][[1]]$ci.ub, heteroCVR_se = .[[2]][[1]]$se,
    heteroVR = .[[3]][[1]]$b, heteroVR_lower = .[[3]][[1]]$ci.lb, heteroVR_upper = .[[3]][[1]]$ci.ub, heteroVR_se = .[[3]][[1]]$se,
    heteroRR = .[[4]][[1]]$b, heteroRR_lower = .[[4]][[1]]$ci.lb, heteroRR_upper = .[[4]][[1]]$ci.ub, heteroRR_se = .[[4]][[1]]$se
  ) %>%
  select(., GroupingTerm, heteroCVR:heteroRR_se)

Eye. <- heterog1 %>%
  filter(., GroupingTerm == "Eye") %>%
  select(., -data) %>%
  mutate(
    heteroCVR = .[[2]][[1]]$b, heteroCVR_lower = .[[2]][[1]]$ci.lb, heteroCVR_upper = .[[2]][[1]]$ci.ub, heteroCVR_se = .[[2]][[1]]$se,
    heteroVR = .[[3]][[1]]$b, heteroVR_lower = .[[3]][[1]]$ci.lb, heteroVR_upper = .[[3]][[1]]$ci.ub, heteroVR_se = .[[3]][[1]]$se,
    heteroRR = .[[4]][[1]]$b, heteroRR_lower = .[[4]][[1]]$ci.lb, heteroRR_upper = .[[4]][[1]]$ci.ub, heteroRR_se = .[[4]][[1]]$se
  ) %>%
  select(., GroupingTerm, heteroCVR:heteroRR_se)

heterog2 <- bind_rows(Behaviour., Morphology., Metabolism., Physiology., Immunology., Hematology., Heart., Hearing., Eye.)
# str(heterog2)

Heterogeneity PLOT

Restructure data for plotting

heterog3 <- gather(heterog2, parameter, value, c(heteroCVR, heteroVR, heteroRR), factor_key = TRUE)

heteroCVR.ci <- heterog3 %>%
  filter(parameter == "heteroCVR") %>%
  mutate(ci.low = heteroCVR_lower, ci.high = heteroCVR_upper)
heteroVR.ci <- heterog3 %>%
  filter(parameter == "heteroVR") %>%
  mutate(ci.low = heteroVR_lower, ci.high = heteroVR_upper)
heteroRR.ci <- heterog3 %>%
  filter(parameter == "heteroRR") %>%
  mutate(ci.low = heteroRR_lower, ci.high = heteroRR_upper)

heterog4 <- bind_rows(heteroCVR.ci, heteroVR.ci, heteroRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high)

# **Re-order grouping terms

heterog4$GroupingTerm <- factor(heterog4$GroupingTerm, levels = c("Behaviour", "Morphology", "Metabolism", "Physiology", "Immunology", "Hematology", "Heart", "Hearing", "Eye"))
heterog4$GroupingTerm <- factor(heterog4$GroupingTerm, rev(levels(heterog4$GroupingTerm)))
heterog4$label <- "All traits"
# write.csv(heterog4, "heterog4.csv")

Plot FIGURE 4 - C(Second-order meta analysis on heterogeneity)

Plot Fig4 all traits

heterog5 <- heterog4
heterog5$mean <- as.numeric(exp(heterog5$value))
heterog5$ci.l <- as.numeric(exp(heterog5$ci.low))
heterog5$ci.h <- as.numeric(exp(heterog5$ci.high))

heterog6 <- heterog5

Hetero4c <-
  heterog6 %>%
  filter(
    parameter == "heteroCVR" | parameter == "heteroRR"
  ) %>%
  ggplot(aes(y = GroupingTerm, x = mean)) +
  geom_errorbarh(aes(
    xmin = ci.l,
    xmax = ci.h
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(shape = parameter),
    fill = "black",
    color = "black", size = 2.2,
    show.legend = FALSE
  ) +
  scale_x_continuous(
    limits = c(-0.1, 1.4),
    # breaks = c(0, 0.1, 0.2),
    name = "sigma^2"
  ) +
  # geom_vline(xintercept=0,
  # color='black',
  # linetype='dashed')+
  facet_grid(
    cols = vars(parameter), rows = vars(label),
    labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_text(hjust = 0.5, size = 14),
    axis.title.y = element_blank()
  )

# Hetero4c

# ggsave("Fig4.pdf", plot = Metameta_Fig4_alltraits, width = 7, height = 6)

Combined Figure 4: overall (Count data, Meta anlysis results, Heterogeneity)


Fig4 <- ggarrange(malebias_Fig2_alltraits, Metameta_Fig3_alltraits, Hetero4c, nrow = 3, align = "v", heights = c(1, 1, 1), labels = c("A", "B", "C"))
Fig4
# ggsave("Fig4_OverallResults.pdf", plot = Fig4, width = 6, height = 5)

Supplemental Figures

## Heterogneity, S1 C

HeteroS1 <- heterog5 %>%
  ggplot(aes(y = GroupingTerm, x = mean)) +
  geom_errorbarh(aes(
    xmin = ci.l,
    xmax = ci.h
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(shape = parameter),
    fill = "black",
    color = "black", size = 2.2,
    show.legend = FALSE
  ) +
  scale_x_continuous(
    limits = c(-0.1, 1.4),
    # breaks = c(0, 0.1, 0.2),
    name = "Effect size"
  ) +
  # geom_vline(xintercept=0,
  # color='black',
  # linetype='dashed')+
  facet_grid(
    cols = vars(parameter), rows = vars(label),
    labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  )

# HeteroS1

# ggsave("Fig4.pdf", plot = Metameta_Fig4_alltraits, width = 7, height = 6)

Count data, including lnVR (Fig S1 A)

# *Prepare data for all traits

meta.plot2.all <- meta_clean %>%
  select(lnCVR, lnVR, lnRR, GroupingTerm) %>%
  arrange(GroupingTerm)

meta.plot2.all.bS1 <- gather(meta.plot2.all, trait, value, c(lnCVR, lnVR, lnRR))

meta.plot2.all.bS1$trait <- factor(meta.plot2.all.bS1$trait, levels = c("lnCVR", "lnVR", "lnRR"))

meta.plot2.all.cS1 <- meta.plot2.all.bS1 %>%
  group_by_at(vars(trait, GroupingTerm)) %>%
  summarise(
    malebias = sum(value > 0), femalebias = sum(value <= 0), total = malebias + femalebias,
    malepercent = malebias * 100 / total, femalepercent = femalebias * 100 / total
  )

meta.plot2.all.cS1$label <- "All traits"

# restructure to create stacked bar plots

meta.plot2.all.dS1 <- as.data.frame(meta.plot2.all.cS1)
meta.plot2.all.eS1 <- gather(meta.plot2.all.dS1, key = sex, value = percent, malepercent:femalepercent, factor_key = TRUE)

# create new sample size variable

meta.plot2.all.eS1$samplesize <- with(meta.plot2.all.eS1, ifelse(sex == "malepercent", malebias, femalebias))

malebias_FigS1_alltraits <-
  ggplot(meta.plot2.all.eS1) +
  aes(x = GroupingTerm, y = percent, fill = sex) +
  geom_col() +
  geom_hline(yintercept = 50, linetype = "dashed", color = "gray40") +
  geom_text(
    data = subset(meta.plot2.all.eS1, samplesize != 0), aes(label = samplesize), position = position_stack(vjust = .5),
    color = "white", size = 3.5
  ) +
  facet_grid(
    cols = vars(trait), rows = vars(label), labeller = label_wrap_gen(width = 18),
    scales = "free", space = "free"
  ) +
  scale_fill_brewer(palette = "Set2") +
  theme_bw(base_size = 18) +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.position = "none",
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  ) +
  coord_flip()

# malebias_FigS1_alltraits     #(panel A in Figure S1)

Overall results of second order meta analysis (Figure 4: overall, Figure 5: sex-bias), INCLUDING VR

Restructure data for plotting

Restructure MALE data for plotting

overall3.male.sigS <- gather(overall.male.plot3, parameter, value, c(lnCVR, lnVR, lnRR), factor_key = TRUE)

lnCVR.ci <- overall3.male.sigS %>%
  filter(parameter == "lnCVR") %>%
  mutate(ci.low = lnCVR_lower, ci.high = lnCVR_upper)
lnVR.ci <- overall3.male.sigS %>%
  filter(parameter == "lnVR") %>%
  mutate(ci.low = lnVR_lower, ci.high = lnVR_upper)
lnRR.ci <- overall3.male.sigS %>%
  filter(parameter == "lnRR") %>%
  mutate(ci.low = lnRR_lower, ci.high = lnRR_upper)

overall4.male.sigS <- bind_rows(lnCVR.ci, lnVR.ci, lnRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high)

overall4.male.sigS$label <- "CI not overlapping zero"

Data are restructured, and grouping terms are being re-ordered

overall3S <- gather(overall2, parameter, value, c(lnCVR, lnVR, lnRR), factor_key = TRUE)

lnCVR.ci <- overall3S %>%
  filter(parameter == "lnCVR") %>%
  mutate(ci.low = lnCVR_lower, ci.high = lnCVR_upper)
lnVR.ci <- overall3S %>%
  filter(parameter == "lnVR") %>%
  mutate(ci.low = lnVR_lower, ci.high = lnVR_upper)
lnRR.ci <- overall3S %>%
  filter(parameter == "lnRR") %>%
  mutate(ci.low = lnRR_lower, ci.high = lnRR_upper)

overall4S <- bind_rows(lnCVR.ci, lnVR.ci, lnRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high)

# re-order Grouping Terms

overall4S$GroupingTerm <- factor(overall4S$GroupingTerm, levels = c("Behaviour", "Morphology", "Metabolism", "Physiology", "Immunology", "Hematology", "Heart", "Hearing", "Eye", "All"))
overall4S$GroupingTerm <- factor(overall4S$GroupingTerm, rev(levels(overall4S$GroupingTerm)))
overall4S$label <- "All traits"

Preparation for Plots FIGURE S1B & S2B, S2D (Second-order meta analysis results, INCL lnVR)

Preparation: Sub-Plot for Figure S1: all traits (S1 B)

Metameta_FigS1_alltraits <- overall4S %>%

  ggplot(aes(y = GroupingTerm, x = value)) +
  geom_errorbarh(aes(
    xmin = ci.low,
    xmax = ci.high
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(shape = parameter),
    fill = "black",
    color = "black", size = 2.2,
    show.legend = FALSE
  ) +
  scale_x_continuous(
    limits = c(-0.24, 0.25),
    breaks = c(-0.2, -0.1, 0, 0.1, 0.2),
    name = "Effect size"
  ) +
  geom_vline(
    xintercept = 0,
    color = "black",
    linetype = "dashed"
  ) +
  facet_grid(
    cols = vars(parameter), rows = vars(label),
    labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_text(hjust = 0.5, size = 14),
    axis.title.y = element_blank()
  )

# Metameta_FigS1_alltraits

Combined Figure S1: overall Count data, Meta anlysis results, Heterogeneity)

FigS1 <- ggarrange(malebias_FigS1_alltraits + xlab("percentage sex bias"), Metameta_FigS1_alltraits, HeteroS1, nrow = 3, align = "v", heights = c(1, 1, 1), labels = c("A", "B", "C"))
FigS1
# ggsave("FigS1_OverallResults.pdf", plot = Fig4, width = 6, height = 5)

Figure S2: sex-bias, including VR

Plot FigS2 all significant results (CI not overlapping zero) for males

meta.plot2.sig.bS <- meta.plot2.sig[, c("lnCVR", "lnVR", "lnRR", "lnCVRsig", "lnVRsig", "lnRRsig", "GroupingTerm")]

meta.plot2.sig.cS <- gather(meta.plot2.sig.bS, trait, value, lnCVR:lnRR)
meta.plot2.sig.cS$sig <- "placeholder"

meta.plot2.sig.cS$trait <- factor(meta.plot2.sig.cS$trait, levels = c("lnCVR", "lnVR", "lnRR"))

meta.plot2.sig.cS$sig <- ifelse(meta.plot2.sig.cS$trait == "lnCVR", meta.plot2.sig.cS$lnCVRsig,
  ifelse(meta.plot2.sig.cS$trait == "lnVR", meta.plot2.sig.cS$lnVRsig, meta.plot2.sig.cS$lnRRsig)
)

# choosing sex biased ln-ratios significantly larger than 0
meta.plotS2.sig.malebias <- meta.plot2.sig.cS %>%
  group_by_at(vars(trait, GroupingTerm)) %>%
  filter(sig == 1) %>%
  summarise(male_sig = sum(value > 0), female_sig = sum(value < 0), total = male_sig + female_sig)

meta.plotS2.sig.malebias <- ungroup(meta.plotS2.sig.malebias) %>%
  add_row(trait = "lnCVR", GroupingTerm = "Hearing", male_sig = 0, female_sig = 0, .before = 4) %>% # add "Hearing" for lnCVR (not filtered as only zeros)
  mutate(malepercent = male_sig * 100 / total, femalepercent = female_sig * 100 / total)

meta.plotS2.sig.malebias$label <- "CI not overlapping zero"

# restructure to create stacked bar plots

meta.plotS2.sig.bothsexes <- as.data.frame(meta.plotS2.sig.malebias)
meta.plotS2.sig.bothsexes.b <- gather(meta.plotS2.sig.bothsexes, key = sex, value = percent, malepercent:femalepercent, factor_key = TRUE)

# create new sample size variable

meta.plotS2.sig.bothsexes.b$samplesize <- with(meta.plotS2.sig.bothsexes.b, ifelse(sex == "malepercent", male_sig, female_sig))

# *Plot Fig2 all significant results (CI not overlapping zero):
#     no sig. lnCVR for 'Hearing' in either sex; no sig. male-biased lnCVR for 'Immunology' and 'Eye, and no sig. male-biased lnVR for 'Eye'


malebias_FigS2_sigtraits <-
  ggplot(meta.plotS2.sig.bothsexes.b) +
  aes(x = GroupingTerm, y = percent, fill = sex) +
  geom_col() +
  geom_hline(yintercept = 50, linetype = "dashed", color = "gray40") +
  geom_text(
    data = subset(meta.plotS2.sig.bothsexes.b, samplesize != 0), aes(label = samplesize), position = position_stack(vjust = .5),
    color = "white", size = 3.5
  ) +
  facet_grid(
    cols = vars(trait), rows = vars(label), labeller = label_wrap_gen(width = 18),
    scales = "free", space = "free"
  ) +
  scale_fill_brewer(palette = "Set2") +
  theme_bw(base_size = 18) +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.position = "none",
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  ) +
  coord_flip()

# malebias_FigS2_sigtraits # this is Figure S2 A

Prepare data for traits with effect size ratios > 10% larger in males

meta.plotS2.over10 <- meta_clean %>%
  select(lnCVR, lnVR, lnRR, GroupingTerm) %>%
  arrange(GroupingTerm)

meta.plotS2.over10.b <- gather(meta.plotS2.over10, trait, value, c(lnCVR, lnVR, lnRR))

meta.plotS2.over10.b$trait <- factor(meta.plotS2.over10.b$trait, levels = c("lnCVR", "lnVR", "lnRR"))

meta.plotS2.over10.c <- meta.plotS2.over10.b %>%
  group_by_at(vars(trait, GroupingTerm)) %>%
  summarise(
    malebias = sum(value > log(11 / 10)), femalebias = sum(value < log(9 / 10)), total = malebias + femalebias,
    malepercent = malebias * 100 / total, femalepercent = femalebias * 100 / total
  )

meta.plotS2.over10.c$label <- "Sex difference in m/f ratios > 10%"

# restructure to create stacked bar plots

meta.plotS2.over10.c <- as.data.frame(meta.plotS2.over10.c)
meta.plotS2.over10.d <- gather(meta.plotS2.over10.c, key = sex, value = percent, malepercent:femalepercent, factor_key = TRUE)

# create new sample size variable

meta.plotS2.over10.d$samplesize <- with(meta.plotS2.over10.d, ifelse(sex == "malepercent", malebias, femalebias))

# *Plot FigS2 Sex difference in m/f ratio > 10%
malebias_FigS2_over10 <-
  ggplot(meta.plotS2.over10.d) +
  aes(x = GroupingTerm, y = percent, fill = sex) +
  geom_col() +
  geom_hline(yintercept = 50, linetype = "dashed", color = "gray40") +
  geom_text(
    data = subset(meta.plot2.over10.d, samplesize != 0), aes(label = samplesize), position = position_stack(vjust = .5),
    color = "white", size = 3.5
  ) +
  facet_grid(
    cols = vars(trait), rows = vars(label), labeller = label_wrap_gen(width = 18),
    scales = "free", space = "free"
  ) +
  scale_fill_brewer(palette = "Set2") +
  theme_bw(base_size = 18) +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_blank(),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.position = "none",
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  ) +
  coord_flip()

# malebias_FigS2_over10  #(Panel B in Fig S2 in ms)

Female Figure, significant traits

Female FigS2 B sig

Prepare data for traits with CI not overlapping 0 create column with 1= different from zero, 0= zero included in CI

Restructure data for plotting

overall3.female.sigS <- gather(overall.female.plot3, parameter, value, c(lnCVR, lnVR, lnRR), factor_key = TRUE)

lnCVR.ci <- overall3.female.sigS %>%
  filter(parameter == "lnCVR") %>%
  mutate(ci.low = lnCVR_lower, ci.high = lnCVR_upper)
lnVR.ci <- overall3.female.sigS %>%
  filter(parameter == "lnVR") %>%
  mutate(ci.low = lnVR_lower, ci.high = lnVR_upper)
lnRR.ci <- overall3.female.sigS %>%
  filter(parameter == "lnRR") %>%
  mutate(ci.low = lnRR_lower, ci.high = lnRR_upper)

overall4.female.sigS <- bind_rows(lnCVR.ci, lnVR.ci, lnRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high)

overall4.female.sigS$label <- "CI not overlapping zero"

##

Metameta_FigS2_female.sig <- overall4.female.sigS %>%
  ggplot(aes(y = GroupingTerm, x = value)) +
  geom_errorbarh(aes(
    xmin = ci.low,
    xmax = ci.high
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(shape = parameter),
    fill = "salmon1", color = "salmon1", size = 2.2,
    show.legend = FALSE
  ) +
  scale_x_continuous(
    limits = c(-0.4, 0),
    breaks = c(-0.3, 0),
    name = "Effect size"
  ) +
  geom_vline(
    xintercept = 0,
    color = "black",
    linetype = "dashed"
  ) +
  facet_grid(
    cols = vars(parameter), # rows = vars(label),
    # labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  )

# Metameta_FigS2_female.sig

#Metameta_FigS2_male.sig (Figure 5B right panel)

Restructure MALE data for plotting

overall3.male.sigS <- gather(overall.male.plot3, parameter, value, c(lnCVR, lnVR, lnRR), factor_key = TRUE)


lnCVR.ci <- overall3.male.sigS %>%
  filter(parameter == "lnCVR") %>%
  mutate(ci.low = lnCVR_lower, ci.high = lnCVR_upper)
lnVR.ci <- overall3.male.sigS %>%
  filter(parameter == "lnVR") %>%
  mutate(ci.low = lnVR_lower, ci.high = lnVR_upper)
lnRR.ci <- overall3.male.sigS %>%
  filter(parameter == "lnRR") %>%
  mutate(ci.low = lnRR_lower, ci.high = lnRR_upper)

overall4.male.sigS <- bind_rows(lnCVR.ci, lnVR.ci, lnRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high)

overall4.male.sigS$label <- "CI not overlapping zero"

Plot FigS2 all significant results (CI not overlapping zero, male )

Metameta_FigS2_male.sig <- overall4.male.sigS %>%
  ggplot(aes(y = GroupingTerm, x = value)) +
  geom_errorbarh(aes(
    xmin = ci.low,
    xmax = ci.high
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(shape = parameter),
    fill = "mediumaquamarine", color = "mediumaquamarine", size = 2.2,
    show.legend = FALSE
  ) +
  scale_x_continuous(
    limits = c(0, 0.4),
    breaks = c(0, 0.3),
    name = "Effect size"
  ) +
  geom_vline(
    xintercept = 0,
    color = "black",
    linetype = "dashed"
  ) +
  facet_grid(
    cols = vars(parameter), rows = vars(label),
    labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_text(size = 12),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_blank(),
    axis.title.y = element_blank()
  )

# Metameta_FigS2_male.sig

10 % Perc sex difference, male bias

Restructure data for plotting : Male biased, 10% difference

overall3S.perc <- gather(overall.male.plot3.perc, parameter, value, c(lnCVR, lnVR, lnRR), factor_key = TRUE) # lnVR,

lnCVR.ci <- overall3S.perc %>%
  filter(parameter == "lnCVR") %>%
  mutate(ci.low = lnCVR_lower, ci.high = lnCVR_upper)
lnVR.ci <- overall3S.perc %>%
  filter(parameter == "lnVR") %>%
  mutate(ci.low = lnVR_lower, ci.high = lnVR_upper)
lnRR.ci <- overall3S.perc %>%
  filter(parameter == "lnRR") %>%
  mutate(ci.low = lnRR_lower, ci.high = lnRR_upper)

overall4S.male.perc <- bind_rows(lnCVR.ci, lnVR.ci, lnRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high) # lnVR.ci,

overall4S.male.perc$label <- "Sex difference in m/f ratios > 10%"

overall4S.male.perc$value <- as.numeric(overall4S.male.perc$value)
overall4S.male.perc$ci.low <- as.numeric(overall4S.male.perc$ci.low)
overall4S.male.perc$ci.high <- as.numeric(overall4S.male.perc$ci.high)

Plot FigS2 all >10% difference (male bias)

Metameta_FigS2_male.perc <- overall4S.male.perc %>% # filter(., GroupingTerm != "Hearing") %>%
  ggplot(aes(y = GroupingTerm, x = value)) +
  geom_errorbarh(aes(
    xmin = ci.low,
    xmax = ci.high
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(
    shape = parameter,
    fill = parameter
  ),
  color = "mediumaquamarine", size = 2.2,
  show.legend = FALSE
  ) +
  scale_x_continuous(
    limits = c(-0.2, 0.62),
    breaks = c(0, 0.3),
    name = "Effect size"
  ) +
  geom_vline(
    xintercept = 0,
    color = "black",
    linetype = "dashed"
  ) +
  facet_grid(
    cols = vars(parameter), rows = vars(label),
    labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_blank(),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_text(hjust = 0.5, size = 14),
    axis.title.y = element_blank()
  )

# Metameta_FigS2_male.perc (Figure 5D right panel)

Restructure data for plotting: Female bias, 10 percent difference, including VR

overall3S.perc <- gather(overall.plot3.perc, parameter, value, c(lnCVR, lnVR, lnRR), factor_key = TRUE) # lnVR,

lnCVR.ci <- overall3S.perc %>%
  filter(parameter == "lnCVR") %>%
  mutate(ci.low = lnCVR_lower, ci.high = lnCVR_upper)
lnVR.ci <- overall3S.perc %>%
  filter(parameter == "lnVR") %>%
  mutate(ci.low = lnVR_lower, ci.high = lnVR_upper)
lnRR.ci <- overall3S.perc %>%
  filter(parameter == "lnRR") %>%
  mutate(ci.low = lnRR_lower, ci.high = lnRR_upper)

overall4S.perc <- bind_rows(lnCVR.ci, lnVR.ci, lnRR.ci) %>% select(GroupingTerm, parameter, value, ci.low, ci.high)

overall4S.perc$label <- "Sex difference in m/f ratios > 10%"

overall4S.perc$value <- as.numeric(overall4S.perc$value)
overall4S.perc$ci.low <- as.numeric(overall4S.perc$ci.low)
overall4S.perc$ci.high <- as.numeric(overall4S.perc$ci.high)

Plot Fig5D all >10% difference (female)

Metameta_Fig3S_female.perc <- overall4S.perc %>%
  ggplot(aes(y = GroupingTerm, x = value)) +
  geom_errorbarh(aes(
    xmin = ci.low,
    xmax = ci.high
  ),
  height = 0.1, show.legend = FALSE
  ) +
  geom_point(aes(shape = parameter),
    fill = "salmon1", color = "salmon1", size = 2.2,
    show.legend = FALSE
  ) +

  # scale_shape_manual(values =

  scale_x_continuous(
    limits = c(-0.53, 0.2),
    breaks = c(-0.3, 0),
    name = "Effect size"
  ) +
  geom_vline(
    xintercept = 0,
    color = "black",
    linetype = "dashed"
  ) +
  facet_grid(
    cols = vars(parameter), # rows = vars(label),
    # labeller = label_wrap_gen(width = 23),
    scales = "free",
    space = "free"
  ) +
  theme_bw() +
  theme(
    strip.text.y = element_text(angle = 270, size = 10, margin = margin(t = 15, r = 15, b = 15, l = 15)),
    strip.text.x = element_blank(),
    strip.background = element_rect(colour = NULL, linetype = "blank", fill = "gray90"),
    text = element_text(size = 14),
    panel.spacing = unit(0.5, "lines"),
    panel.border = element_blank(),
    axis.line = element_line(),
    panel.grid.major.x = element_line(linetype = "solid", colour = "gray95"),
    panel.grid.major.y = element_line(linetype = "solid", color = "gray95"),
    panel.grid.minor.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    legend.title = element_blank(),
    axis.title.x = element_text(hjust = 0.5, size = 14),
    axis.title.y = element_blank()
  )

# Metameta_Fig3S_female.perc (Figure 5D left panel)

Figure S2

FigS2c <- ggarrange(Metameta_FigS2_female.sig, Metameta_FigS2_male.sig,
  ncol = 2, nrow = 1, widths = c(1, 1.20), heights = c(1, 1)
)

FigS2d <- ggarrange(Metameta_Fig3S_female.perc, Metameta_FigS2_male.perc,
  ncol = 2, nrow = 1, widths = c(1, 1.20), heights = c(1, 1)
)

# end combination Figure 5

FigS2 <- ggarrange(malebias_FigS2_sigtraits, malebias_FigS2_over10, FigS2c, FigS2d, ncol = 1, nrow = 4, heights = c(2.2, 2, 2.2, 2), labels = c("A", " ", "B", " "))
FigS2

Acknowledgements

tbd

R Session Information

sessionInfo()
LS0tCnRpdGxlOiAiSU1QQyBNb3VzZSBkYXRhIC0gVmFyaWFuY2UgaW4gc2V4IGRpZmZlcmVuY2VzIgphdXRob3I6ICJTdXNhbm5lIFphaml0c2NoZWssICBGZWxpeCBaYWppdHNjaGVrLCBSdXNzZWxsIEJvbmR1cmlhbnNreSxSb2JlcnQgIEJyb29rcywgV2lsbCBDb3Jud2VsbCwgRGFuaWVsIEZhbHN0ZXIsIE1hbGdvcnRhemEgTGFnaXN6LCBKZXJlbXkgTWFzb24sIERhbmllbCBOb2JsZSwgQWxpc3RhaXIgU2VuaW9yICYgU2hpbmljaGkgTmFrYWdhd2EiCmRhdGU6ICJBdWd1c3QgMjAxOSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGRlcHRoOiA0CiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0aGVtZTogIGZsYXRseQogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgdG9jX2Zsb2F0OiB5ZXMKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnNCcKc3VidGl0bGU6IEVsZWN0cm9uaWMgU3VwcGxlbWVudGFyeSBNYXRlcmlhbAotLS0KCiMgU2V0LXVwCgojIyBMb2FkaW5nIHBhY2thZ2VzICYgY3VzdG9tIGZ1bmN0aW9ucwoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwKICB3YXJuaW5nID0gRkFMU0UsCiAgbWVzc2FnZSA9IEZBTFNFLAogIGNhY2hlID0gVFJVRSwKICB0aWR5ID0gVFJVRQopCmBgYAoKYGBge3J9CmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkobWV0YWZvcikKbGlicmFyeShkZXZ0b29scykKbGlicmFyeShwdXJycikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkocm9idW1ldGEpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoaGVyZSkKYGBgCgpGdW5jdGlvbnMgZm9yIHByZXBhcmluZyB0aGUgZGF0YSBmb3IgbWV0YSBhbmFseXNlcwoKMSkgIlBvcHVsYXRpb24gc3RhdGlzdGljcyI6ICJjYWxjdWxhdGVfcG9wdWxhdGlvbl9zdGF0cyIKVGhpcyBmdW5jdGlvbiBncm91cHMgYW5pbWFscyBmcm9tIHRoZSBzYW1lIHN0cmFpbiBhbmQgc2FtZSBpbnNpdGl1dGlvbiB0b2dldGhlci4gVGhpcyBpcyBkb25lIGZvciBlYWNoIHRyYWl0IHNlb2FyYXRlbHksIGFuZCBvbmx5IGZvciB0cmFpdHMgdGhhdCBoYXZlIGJlZW4gbWVhc3VyZWQgaW4gYm90aCBzZXhlcy4gQW55IGdyb3VwIGNvbnRhaW5pbmcgZmV3ZXIgdGhhbiA1IGluZGl2aWR1YWxzIGlzIGV4Y2x1ZGVkLgoKYGBge3J9CmNhbGN1bGF0ZV9wb3B1bGF0aW9uX3N0YXRzIDwtIGZ1bmN0aW9uKG15ZGF0YSwgbWluX2luZGl2aWR1YWxzID0gNSkgewogIG15ZGF0YSAlPiUKICAgIGdyb3VwX2J5KHBvcHVsYXRpb24sIHN0cmFpbl9uYW1lLCBwcm9kdWN0aW9uX2NlbnRlciwgc2V4KSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgdHJhaXQgPSBwYXJhbWV0ZXJfbmFtZVsxXSwKICAgICAgeF9iYXIgPSBtZWFuKGRhdGFfcG9pbnQpLAogICAgICB4X3NkID0gc2QoZGF0YV9wb2ludCksCiAgICAgIG5faW5kID0gbigpCiAgICApICU+JQogICAgdW5ncm91cCgpICU+JQogICAgZmlsdGVyKG5faW5kID4gbWluX2luZGl2aWR1YWxzKSAlPiUKICAgICMgQ2hlY2sgYm90aCBzZXhlcyBwcmVzZW50ICYgZmlsdGVyIHRob3NlIG1pc3NpbmcKICAgIGdyb3VwX2J5KHBvcHVsYXRpb24pICU+JQogICAgbXV0YXRlKAogICAgICBuX3NleCA9IG5fZGlzdGluY3Qoc2V4KQogICAgKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIGZpbHRlcihuX3NleCA9PSAyKSAlPiUKICAgIHNlbGVjdCgtbl9zZXgpICU+JQogICAgYXJyYW5nZShwcm9kdWN0aW9uX2NlbnRlciwgc3RyYWluX25hbWUsIHBvcHVsYXRpb24sIHNleCkKfQpgYGAKCjIpIEV4dHJhY3Rpb24gb2YgZWZmZWN0IHNpemVzIGFuZCBzYW1wbGUgdmFyaWFuY2VzOiAiY3JlYXRlX21ldGFfYW5hbHlzaXNfZWZmZWN0X3NpemVzIgoKYGBge3J9CmNyZWF0ZV9tZXRhX2FuYWx5c2lzX2VmZmVjdF9zaXplcyA8LSBmdW5jdGlvbihteWRhdGEpIHsKICBpIDwtIHNlcSgxLCBucm93KG15ZGF0YSksIGJ5ID0gMikKICBpbnB1dCA8LSBkYXRhLmZyYW1lKAogICAgbjFpID0gbXlkYXRhJG5faW5kW2ldLAogICAgbjJpID0gbXlkYXRhJG5faW5kW2kgKyAxXSwKICAgIHgxaSA9IG15ZGF0YSR4X2JhcltpXSwKICAgIHgyaSA9IG15ZGF0YSR4X2JhcltpICsgMV0sCiAgICBzZDFpID0gbXlkYXRhJHhfc2RbaV0sCiAgICBzZDJpID0gbXlkYXRhJHhfc2RbaSArIDFdCiAgKQoKICBteWRhdGFbaSwgXSAlPiUKICAgIHNlbGVjdChzdHJhaW5fbmFtZSwgcHJvZHVjdGlvbl9jZW50ZXIsIHRyYWl0KSAlPiUKICAgIG11dGF0ZSgKICAgICAgZWZmZWN0X3NpemVfQ1ZSID0gY2FsY3VsYXRlX2xuQ1ZSKENNZWFuID0gaW5wdXQkeDFpLCBDU0QgPSBpbnB1dCRzZDFpLCBDTiA9IGlucHV0JG4xaSwgRU1lYW4gPSBpbnB1dCR4MmksIEVTRCA9IGlucHV0JHNkMmksIEVOID0gaW5wdXQkbjJpKSwKICAgICAgc2FtcGxlX3ZhcmlhbmNlX0NWUiA9IGNhbGN1bGF0ZV92YXJfbG5DVlIoQ01lYW4gPSBpbnB1dCR4MWksIENTRCA9IGlucHV0JHNkMWksIENOID0gaW5wdXQkbjFpLCBFTWVhbiA9IGlucHV0JHgyaSwgRVNEID0gaW5wdXQkc2QyaSwgRU4gPSBpbnB1dCRuMmkpLAogICAgICBlZmZlY3Rfc2l6ZV9WUiA9IGNhbGN1bGF0ZV9sblZSKENTRCA9IGlucHV0JHNkMWksIENOID0gaW5wdXQkbjFpLCBFU0QgPSBpbnB1dCRzZDJpLCBFTiA9IGlucHV0JG4yaSksCiAgICAgIHNhbXBsZV92YXJpYW5jZV9WUiA9IGNhbGN1bGF0ZV92YXJfbG5WUihDTiA9IGlucHV0JG4xaSwgRU4gPSBpbnB1dCRuMmkpLAogICAgICBlZmZlY3Rfc2l6ZV9SUiA9IGNhbGN1bGF0ZV9sblJSKENNZWFuID0gaW5wdXQkeDFpLCBDU0QgPSBpbnB1dCRzZDFpLCBDTiA9IGlucHV0JG4xaSwgRU1lYW4gPSBpbnB1dCR4MmksIEVTRCA9IGlucHV0JHNkMmksIEVOID0gaW5wdXQkbjJpKSwKICAgICAgc2FtcGxlX3ZhcmlhbmNlX1JSID0gY2FsY3VsYXRlX3Zhcl9sblJSKENNZWFuID0gaW5wdXQkeDFpLCBDU0QgPSBpbnB1dCRzZDFpLCBDTiA9IGlucHV0JG4xaSwgRU1lYW4gPSBpbnB1dCR4MmksIEVTRCA9IGlucHV0JHNkMmksIEVOID0gaW5wdXQkbjJpKSwKICAgICAgZXJyID0gYXMuZmFjdG9yKHNlcV9sZW4obigpKSkKICAgICkKfQpgYGAKCiAKMykgQ2FsY3VsYXRlIG1ldGEtYW5hbHlzaXMgc3RhdGlzdGljcwoKQmFzZWQgb24gZnVuY3Rpb24gY3JlYXRlZCBieSBBIE0gU2VuaW9yIEAgdGhlIFVuaXZlcnNpdHkgb2YgT3RhZ28gTlogMDMvMDEvMjAxNDogCgoqIENhbGN1bGF0ZXMgZWZmZWN0IHNpemVzIGZvciBtZXRhLWFuYWx5c2lzIG9mIHZhcmlhbmNlLiAgQWxsIGZ1bmN0aW9ucyB0YWtlIHRoZSBtZWFuLCBzZCBhbmQgbiBmcm9tIHRoZSBjb250cm9sIGFuZCBleHBlcmltZW50YWwgZ3JvdXBzLgoqIFRoZSBmaXJzdCBmdW5jdGlvbiwgY2FsY3VsYXRlX2xuQ1ZSLCBjYWxjdWxhdGVzIHRoZSB0aGUgbG9nIHJlc3BvbnNlLXJhdGlvIG9mIHRoZSBjb2VmZmljaWVudCBvZiB2YXJpYW5jZSAobG5DVlIpIC0gc2VlIE5ha2FnYXdhIGV0IGFsIDIwMTUuCiogVGhlIHNlY29uZCBmdW5jdGlvbiBjYWxjdWxhdGVzIHRoZSBtZWFzdXJlbWVudCBlcnJvciB2YXJpYW5jZSBmb3IgbG5DVlIuIEFzIHdlbGwgYXMgdGhlIGFmb3JlbWVudGlvbmVkIHBhcmFtZXRlcnMsIHRoaXMgZnVuY3Rpb24gYWxzbyB0YWtlcyBFcXVhbF9FX0NfQ29yciAoZGVmYXVsdCA9IFQpLCB3aGljaCBtdXN0IGJlIFRydWUgb3IgRmFsc2UuIElmIHRydWUsIHRoZSBmdW5jdGlvbiBhc3N1bWVzIHRoYXQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gbWVhbiBhbmQgc2QgKFRheWxvcidzIExhdykgIGlzIGVxdWFsIGZvciB0aGUgbWVhbiBhbmQgY29udHJvbCBncm91cHMsIGFuZCwgdGh1cyB0aGVzZSBkYXRhIGFyZSBwb29sZWQuIElmIEZhbHNlIHRoZSBtZWFuLVNEIGNvcnJlbGF0aW9uIGZvciB0aGUgZXhwZXJpbWVudGFsIGFuZCBjb250cm9sIGdyb3VwcyBhcmUgY2FsY3VsYXRlZCBzZXBhcmF0ZWx5IGZyb20gb25lIGFub3RoZXIuCiogU2ltaWxhciBmdW5jdGlvbnMgYXJlIHRoZW4gaW1wbGVtZW50ZWQgZm9yIGxuVlIgKGZvciBjb21wYXJpc29uIG9mIHN0YW5kYXJkIGRldmlhdGlvbnMpIGFuZCBsbiBSUiAgKGZvciBjb21wYXJpc29uIG9mIG1lYW5zKSAKIAoKYGBge3J9CgpjYWxjdWxhdGVfbG5DVlIgPC0gZnVuY3Rpb24oQ01lYW4sIENTRCwgQ04sIEVNZWFuLCBFU0QsIEVOKSB7CiAgbG9nKEVTRCkgLSBsb2coRU1lYW4pICsgMSAvICgyICogKEVOIC0gMSkpIC0gKGxvZyhDU0QpIC0gbG9nKENNZWFuKSArIDEgLyAoMiAqIChDTiAtIDEpKSkKfQoKY2FsY3VsYXRlX3Zhcl9sbkNWUiA8LSBmdW5jdGlvbihDTWVhbiwgQ1NELCBDTiwgRU1lYW4sIEVTRCwgRU4sIEVxdWFsX0VfQ19Db3JyID0gVCkgewogIGlmIChFcXVhbF9FX0NfQ29yciA9PSBUKSB7CiAgICBtdmNvcnIgPC0gMCAjIGNvci50ZXN0KGxvZyhjKENNZWFuLCBFTWVhbikpLCBsb2coYyhDU0QsIEVTRCkpKSRlc3RpbWF0ZSAgIG9sZCwgc2xpZ2h0bHkgaW5jb3JyZWN0CiAgICBTMiA8LSBDU0ReMiAvIChDTiAqIChDTWVhbl4yKSkgKyAxIC8gKDIgKiAoQ04gLSAxKSkgLSAyICogbXZjb3JyICogc3FydCgoQ1NEXjIgLyAoQ04gKiAoQ01lYW5eMikpKSAqICgxIC8gKDIgKiAoQ04gLSAxKSkpKSArIEVTRF4yIC8gKEVOICogKEVNZWFuXjIpKSArIDEgLyAoMiAqIChFTiAtIDEpKSAtIDIgKiBtdmNvcnIgKiBzcXJ0KChFU0ReMiAvIChFTiAqIChFTWVhbl4yKSkpICogKDEgLyAoMiAqIChFTiAtIDEpKSkpCiAgfQogIGVsc2UgewogICAgQ212Y29yciA8LSBjb3IudGVzdChsb2coQ01lYW4pLCBsb2coQ1NEKSkkZXN0aW1hdGUKICAgIEVtdmNvcnIgPC0gY29yLnRlc3QobG9nKEVNZWFuKSwgKEVTRCkpJGVzdGltYXRlCiAgICBTMiA8LSBDU0ReMiAvIChDTiAqIChDTWVhbl4yKSkgKyAxIC8gKDIgKiAoQ04gLSAxKSkgLSAyICogQ212Y29yciAqIHNxcnQoKENTRF4yIC8gKENOICogKENNZWFuXjIpKSkgKiAoMSAvICgyICogKENOIC0gMSkpKSkgKyBFU0ReMiAvIChFTiAqIChFTWVhbl4yKSkgKyAxIC8gKDIgKiAoRU4gLSAxKSkgLSAyICogRW12Y29yciAqIHNxcnQoKEVTRF4yIC8gKEVOICogKEVNZWFuXjIpKSkgKiAoMSAvICgyICogKEVOIC0gMSkpKSkKICB9CiAgUzIKfQoKY2FsY3VsYXRlX2xuVlIgPC0gZnVuY3Rpb24oQ1NELCBDTiwgRVNELCBFTikgewogIGxvZyhFU0QpIC0gbG9nKENTRCkgKyAxIC8gKDIgKiAoRU4gLSAxKSkgLSAxIC8gKDIgKiAoQ04gLSAxKSkKfQoKY2FsY3VsYXRlX3Zhcl9sblZSIDwtIGZ1bmN0aW9uKENOLCBFTikgewogIDEgLyAoMiAqIChFTiAtIDEpKSArIDEgLyAoMiAqIChDTiAtIDEpKQp9CgpjYWxjdWxhdGVfbG5SUiA8LSBmdW5jdGlvbihDTWVhbiwgQ1NELCBDTiwgRU1lYW4sIEVTRCwgRU4pIHsKICBsb2coRU1lYW4pIC0gbG9nKENNZWFuKQp9CgpjYWxjdWxhdGVfdmFyX2xuUlIgPC0gZnVuY3Rpb24oQ01lYW4sIENTRCwgQ04sIEVNZWFuLCBFU0QsIEVOKSB7CiAgQ1NEXjIgLyAoQ04gKiBDTWVhbl4yKSArIEVTRF4yIC8gKEVOICogRU1lYW5eMikKfQpgYGAKCiMjIExvYWQgJiBjbGVhbiBkYXRhCgoxKSBEYXRhIGxvYWRpbmcgYW5kIGNsZWFuaW5nIG9mIHRoZSBjc3YgZmlsZQoKVGhpcyBzdGVwIHdlIGhhdmUgYWxyZWFkeSBkb25lIGFuZCBwcm92aWRlIGEgY2xlYW5lZCB1cCBmaWxlIHdoaWNoIGlzIGxlc3MgY29tcHV0aW5nIGludGVuc2l2ZSBhbmQgd2hpY2ggd2UgaGF2ZSBzYXZlZCBpbiBhIGZvbGRlciBjYWxsZWQgYGV4cG9ydGAuIEhvd2V2ZXIsIHRoZSBjdnMgaXMgcHJvdmlkZWQgaW4gY2FzZSB0aGlzIGlzIHByZWZlcnJlZCB0byBiZSBhdHRlbXB0ZWQsIGZvbGxvd2luZyB0aGUgc3RlcHMgYmVsb3c6CgpgYGB7ciBjbGVhbiwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQojIGxvYWRzIHRoZSByYXcgZGF0YSwgc2V0dGluZyBzb21lIGRlZmF1bHQgdHlwZXMgZm9yIHZhcmlvdXMgY29sdW1ucwoKbG9hZF9yYXcgPC0gZnVuY3Rpb24oZmlsZW5hbWUpIHsKICByZWFkX2NzdihmaWxlbmFtZSwKICAgIGNvbF90eXBlcyA9IGNvbHMoCiAgICAgIC5kZWZhdWx0ID0gY29sX2NoYXJhY3RlcigpLAogICAgICBwcm9qZWN0X2lkID0gY29sX2NoYXJhY3RlcigpLAogICAgICBpZCA9IGNvbF9jaGFyYWN0ZXIoKSwKICAgICAgcGFyYW1ldGVyX2lkID0gY29sX2NoYXJhY3RlcigpLAogICAgICBhZ2VfaW5fZGF5cyA9IGNvbF9pbnRlZ2VyKCksCiAgICAgIGRhdGVfb2ZfZXhwZXJpbWVudCA9IGNvbF9kYXRldGltZShmb3JtYXQgPSAiIiksCiAgICAgIHdlaWdodCA9IGNvbF9kb3VibGUoKSwKICAgICAgcGhlbm90eXBpbmdfY2VudGVyX2lkID0gY29sX2NoYXJhY3RlcigpLAogICAgICBwcm9kdWN0aW9uX2NlbnRlcl9pZCA9IGNvbF9jaGFyYWN0ZXIoKSwKICAgICAgd2VpZ2h0X2RhdGUgPSBjb2xfZGF0ZXRpbWUoZm9ybWF0ID0gIiIpLAogICAgICBkYXRlX29mX2JpcnRoID0gY29sX2RhdGV0aW1lKGZvcm1hdCA9ICIiKSwKICAgICAgcHJvY2VkdXJlX2lkID0gY29sX2NoYXJhY3RlcigpLAogICAgICBwaXBlbGluZV9pZCA9IGNvbF9jaGFyYWN0ZXIoKSwKICAgICAgYmlvbG9naWNhbF9zYW1wbGVfaWQgPSBjb2xfY2hhcmFjdGVyKCksCiAgICAgIGJpb2xvZ2ljYWxfbW9kZWxfaWQgPSBjb2xfY2hhcmFjdGVyKCksCiAgICAgIHdlaWdodF9kYXlzX29sZCA9IGNvbF9pbnRlZ2VyKCksCiAgICAgIGRhdGFzb3VyY2VfaWQgPSBjb2xfY2hhcmFjdGVyKCksCiAgICAgIGV4cGVyaW1lbnRfaWQgPSBjb2xfY2hhcmFjdGVyKCksCiAgICAgIGRhdGFfcG9pbnQgPSBjb2xfZG91YmxlKCksCiAgICAgIGFnZV9pbl93ZWVrcyA9IGNvbF9pbnRlZ2VyKCksCiAgICAgIGBfdmVyc2lvbl9gID0gY29sX2NoYXJhY3RlcigpCiAgICApCiAgKQp9CgojIEFwcGx5IHNvbWUgc3RhbmRhcmQgY2xlYW5pbmcgdG8gdGhlIGRhdGEKY2xlYW5fcmF3X2RhdGEgPC0gZnVuY3Rpb24obXlkYXRhKSB7CiAgCiAgZ3JvdXAgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YSIsICJQYXJhbWV0ZXJHcm91cGluZy5jc3YiKSkKICAKICB0bXAgPC0gCiAgICBteWRhdGEgJT4lCgogICAgIyBGaWx0ZXIgdG8gSU1QQyBzb3VyY2UgKHJlY29tbWVuZCBieSBKZXJlbWV5IGluIGVtYWlsIHRvIFN1c2kgb24gMjAgQXVnIDIwMTgpCiAgICBmaWx0ZXIoZGF0YXNvdXJjZV9uYW1lID09ICJJTVBDIikgJT4lCgogICAgIyBzdGFuZGFyZGlzZSB0cmFpdCBuYW1lcwogICAgbXV0YXRlKHBhcmFtZXRlcl9uYW1lID0gdG9sb3dlcihwYXJhbWV0ZXJfbmFtZSkpICU+JQoKICAgICMgcmVtb3ZlIGV4dHJlbWUgYWdlcwogICAgZmlsdGVyKGFnZV9pbl9kYXlzID4gMCAmIGFnZV9pbl9kYXlzIDwgNTAwKSAlPiUKCiAgICAjIHJlbW92ZSBOQXMKICAgIGZpbHRlcighaXMubmEoZGF0YV9wb2ludCkpICU+JQoKICAgICMgc3Vic2V0IHRvIHJlYXNvbmFibGUgc2V0IG9mIHZhcmlhYmxlcwogICAgIyBkYXRlX29mX2V4cGVyaW1lbnQ6IEplcmVteSBzdWdnZXN0ZWQgdXNpbmcgYXMgYW4gaW5kaWNhdG9yIG9mIGJhdGNoLWxldmVsIGVmZmVjdHMKICAgIHNlbGVjdChwcm9kdWN0aW9uX2NlbnRlciwgc3RyYWluX25hbWUsIHN0cmFpbl9hY2Nlc3Npb25faWQsIGJpb2xvZ2ljYWxfc2FtcGxlX2lkLCBwaXBlbGluZV9zdGFibGVfaWQsIHByb2NlZHVyZV9ncm91cCwgcHJvY2VkdXJlX25hbWUsIHNleCwgZGF0ZV9vZl9leHBlcmltZW50LCBhZ2VfaW5fZGF5cywgd2VpZ2h0LCBwYXJhbWV0ZXJfbmFtZSwgZGF0YV9wb2ludCkgJT4lIAoKICAgICMgc29ydAogICAgYXJyYW5nZShwcm9kdWN0aW9uX2NlbnRlciwgYmlvbG9naWNhbF9zYW1wbGVfaWQsIGFnZV9pbl9kYXlzKQogICAgICAKICAgICMgZmlsdGVyIHRvIGdyb3VwcyB3aXRoID4gMSBjZW50cmUgIAogICAgIyAqKlJldmlldyoqIC0gcmV0YWluaW5nIG1lcmdlIGhlcmUgdG8gcmV0YWluIG9yZGVyaW5nIG9mIGRhdGEgdXNlZCBpbiBwcmV2aW91cyB2ZXJzaW9uCiAgICAjIHVzdWFsbHkgaSB3b3VsZCB1c2UgbXV0YXRlIGluc3RlYWQgb2YgY3JlYXRpbmcgc3BlcmF0ZSBkYXRhc2V0CiAgICBtZXJnZSh0bXAsIAogICAgICAgICAgdG1wICU+JSBncm91cF9ieShwYXJhbWV0ZXJfbmFtZSkgJT4lCiAgICBzdW1tYXJpc2UoY2VudGVyX3Blcl90cmFpdCA9IGxlbmd0aCh1bmlxdWUocHJvZHVjdGlvbl9jZW50ZXIsIG5hLnJtID0gVFJVRSkpKQogICAgICAgICklPiUKICAgIGZpbHRlcihjZW50ZXJfcGVyX3RyYWl0ID49IDIpICU+JSAKCiAgICAjIERlZmluZSBwb3B1bGF0aW9uIHZhcmlhYmxlCiAgICBtdXRhdGUocG9wdWxhdGlvbiA9IHNwcmludGYoIiVzLSVzIiwgcHJvZHVjdGlvbl9jZW50ZXIsIHN0cmFpbl9uYW1lKSkgJT4lIAoKICAgICMgYWRkIGdyb3VwaW5nIHZhcmlhYmxlOiB0aGVzZSB3ZXJlIGRlY2lkZWQgYmFzZWQgb24gZnVuY3Rpb25hbCBncm91cHMgYW5kIHByb2NlZHVyZXMgCiAgICBtdXRhdGUocGFyYW1ldGVyX2dyb3VwID0gZ3JvdXAkcGFyYW1ldGVyW21hdGNoKHBhcmFtZXRlcl9uYW1lLCBncm91cCRwYXJhbWV0ZXJfbmFtZSldICkgJT4lCiAgICAjIHVzdWFsbHkgaSB3b3VsZCB1c2UgbGVmdF9qb2luCiAgICAgICAgIyBsZWZ0X2pvaW4oYnk9InBhcmFtZXRlcl9uYW1lIiwgCiAgICAjICAgcmVhZF9jc3YoaGVyZSgiZGF0YSIsICJQYXJhbWV0ZXJHcm91cGluZy5jc3YiKSkgJT4lCiAgICAjICAgICBzZWxlY3QoLWlkKQogICAgIyApICU+JQogICAgICAgICAgCiAgICAjIEFzc2lnbiB1bmlxdWUgSURzIChwZXIgdHJhaXQpCiAgICAjIGVhY2ggdW5pcXVlIHBhcmFtZXRlcl9uYW1lICg9dHJhaXQsdXNlIHRyYWl0IHZhcmlhYmxlKSBnZXRzIGEgdW5pcXVlIG51bWJlciAoJ2lkJykKCiAgICAjIFdlIGFkZCBhIG5ldyB2YXJpYWJsZSwgd2hlcmUgcmVkdW5kYW50IHRyYWl0cyBhcmUgY29tYmluZWQKICAgICNbbm90ZSBob3dldmVyLCBhdCB0aGlzIHN0YWdlIHRoZSBkYXRhc2V0IHN0aWxsIGNvbnRhaW5zIG5vbnNlbnNpY2FsIHRyYWl0cywgaS5lLiB0cmFpdHMgdGhhdCBtYXkgbm90IGNvbnRhaW4gYW55IGluZm9ybWF0aW9uIG9uIHZhcmlhbmNlXQogICAgbXV0YXRlKGlkID0gbWF0Y2gocGFyYW1ldGVyX25hbWUsIHVuaXF1ZShwYXJhbWV0ZXJfbmFtZSkpKSAlPiUgCiAgICBhc190aWJibGUoKQp9CgojIExvYWQgcmF3IGRhdGEgLSBzYXZlIGNsZWFuZWQgZGF0YXNldCBhcyBSRFMgZm9yIHJldXNlCmRhdGFfcmF3IDwtIGxvYWRfcmF3KGhlcmUoImRhdGEiLCJkcjcuMF9hbGxfY29udHJvbF9kYXRhLmNzdi5neiIpKQpkaXIuY3JlYXRlKCJleHBvcnQiLCBGLCBGKQoKZGF0YSA8LSBkYXRhX3JhdyAlPiUgCiAgY2xlYW5fcmF3X2RhdGEoKSAKc2F2ZVJEUyhkYXRhLCAiZXhwb3J0L2RhdGFfY2xlYW4ucmRzIikKYGBgCgpGb3IgYW5hbHlzaXMgd2UgbG9hZCB0aGUgUkRTIGNyZWF0ZWQgYWJvdmUgYW5kIG90aGVyIGRhdGFzZXRzOgoKYGBge3IgbG9hZH0KZGF0YSA8LSByZWFkUkRTKGhlcmUoImV4cG9ydCIsICJkYXRhX2NsZWFuLnJkcyIpKSAKCnByb2NlZHVyZXMgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YSIsICJwcm9jZWR1cmVzLmNzdiIpKQoKYGBgCgoKQ2hlY2sgbGVuZ3RoIG9mIGRpZmZlcmVudCB2YXJpYWJsZXMgLyBzYW1wbGUgc2l6ZXM6CgpgYGB7cn0KbGVuZ3RoKHVuaXF1ZShkYXRhJHBhcmFtZXRlcl9uYW1lKSkgIyAyMzIgdHJhaXRzCmxlbmd0aCh1bmlxdWUoZGF0YSRwYXJhbWV0ZXJfZ3JvdXApKSAjIDE2MSBwYXJhbWV0ZXIgZ3JvdXBzCmxlbmd0aCh1bmlxdWUoZGF0YSRwcm9jZWR1cmVfbmFtZSkpICMgMjYgcHJvY2VkdXJlIGdyb3VwcwpsZW5ndGgodW5pcXVlKGRhdGEkYmlvbG9naWNhbF9zYW1wbGVfaWQpKSAjIDI3MTQ3IGluZGl2aWRpYWwgbWljZSAgICNGWiBhZGRlZCAxMS0xMi0yMDE5CiNudW1iZXIgb2YgbWFsZXMgYW5kIGZlbWFsZXMgcGVyIHN0cmFpbiBwZXIgcHJvZHVjdGlvbiBjZW50ZXIgI0ZaIGFkZGVkIDExLTEyLTIwMTkgICMgRk9SIFRBQkxFIFNBTVBMRSBTSVpFUwpkYXRhICU+JSBncm91cF9ieShwcm9kdWN0aW9uX2NlbnRlciwgc3RyYWluX25hbWUpICU+JSBjb3VudChiaW9sb2dpY2FsX3NhbXBsZV9pZCwgc2V4KSAlPiUgY291bnQoc2V4KSAlPiUgcHJpbnQobiA9IEluZikKCgpgYGAKCiMgUGhhc2UgMTogYWNyb3NzIGFsbCB0cmFpdHMKCkNyZWF0ZSBmdW5jdGlvbiBmb3Igc3ViLXNldHRpbmcgdGhlIGRhdGEgdG8gY2hvb3NlIG9ubHkgb25lIGRhdGEgcG9pbnQgcGVyIGluZGl2aWR1YWwgcGVyIHRyYWl0LiBUaGlzIGlzIGEgbmVjZXNzYXJ5IHN0ZXAgZm9yIHRoZSBsb29wIGFjcm9zcyBhbGwgdHJhaXRzCgpgYGB7cn0KCmRhdGFfc3Vic2V0X3BhcmFtZXRlcmlkX2luZGl2aWR1YWxfYnlfYWdlIDwtIGZ1bmN0aW9uKG15ZGF0YSwgcGFyYW1ldGVyLCBhZ2VfbWluPTAsIGFnZV9jZW50ZXI9MTAwKSB7CiAgdG1wIDwtIG15ZGF0YSAlPiUKICAgIGZpbHRlcigKICAgICAgYWdlX2luX2RheXMgPj0gYWdlX21pbiwKICAgICAgaWQgPT0gcGFyYW1ldGVyCiAgICApICU+JQogICAgIyB0YWtlIHJlc3VsdHMgZm9yIHNpbmdsZSBpbmRpdmlkdWFsIGNsb3Nlc3QgdG8gYWdlX2NlbnRlcgogICAgbXV0YXRlKGFnZV9kaWZmID0gYWJzKGFnZV9jZW50ZXIgLSBhZ2VfaW5fZGF5cykpICU+JQogICAgZ3JvdXBfYnkoYmlvbG9naWNhbF9zYW1wbGVfaWQpICU+JQogICAgZmlsdGVyKGFnZV9kaWZmID09IG1pbihhZ2VfZGlmZikpICU+JQogICAgc2VsZWN0KC1hZ2VfZGlmZikjICU+JSAKIyAgICBmaWx0ZXIoIWR1cGxpY2F0ZWQoYmlvbG9naWNhbF9zYW1wbGVfaWQpKQoKICAgIAogICMgc3RpbGwgc29tZSBpbmRpdmlkdWFscyB3aXRoIG11bHRpcGxlIHJlY29yZHMgKGJlY2F1c2Ugc2FtZSBpbmRpdmlkdWFsIGFwcGVhciB1bmRlciBkaWZmZXJlbnQgcHJvY2VkdXJlcywgc28gZmlsdGVyIHRvIG9uZSByZWNvcmQpCiAgaiA8LSBtYXRjaCh1bmlxdWUodG1wJGJpb2xvZ2ljYWxfc2FtcGxlX2lkKSwgdG1wJGJpb2xvZ2ljYWxfc2FtcGxlX2lkKQogIHRtcFtqLCBdIAogIH0KYGBgCgoKTG9vcCBydW5uaW5nIG1ldGEtYW5hbHlzaXMgb24gYWxsIHRyYWl0cwoKKiBUaGUgbG9vcCBjb21iaW5lcyB0aGUgZnVuY3Rpb25zIG1lbnRpb25lZCBhYm92ZSBhbmQgZmlsbHMgdGhlIGRhdGEgbWF0cml4IHdpdGggcmVzdWx0cyBmcm9tIG91ciBtZXRhIGFuYWx5c2lzLiAKKiBFcnJvciBtZXNzYWdlcyBpbmRpY2F0ZSB0cmFpdHMgdGhhdCBlaXRoZXIgZGlkIG5vdCByZWFjaCBjb252ZXJnZW5jZSwgb3IgdGhhdCBkaWQgbm90IHJldHVybiBtZWFuaW5nZnVsIHJlc3VsdHMgaW4gdGhlIG1ldGEtYW5hbHlzaXMsIGR1ZSB0byBhYnNlbmNlIG9mIHZhcmlhbmNlLiBUaG9zZSB0cmFpdHMgd2lsbCBiZSByZW1vdmVkIGluIGxhdGVyIHN0ZXBzLCBvdXRsaW5lZCBiZWxvdy4KCmBgYHtyfQoKKG4gPC0gbGVuZ3RoKHVuaXF1ZShkYXRhJGlkKSkpCgojIENyZWF0ZSBkYXRhZnJhbWUgdG8gc3RvcmUgcmVzdWx0cwpyZXN1bHRzX2FsbHRyYWl0c19ncm91cGluZyA8LSAKICAgIHRpYmJsZShpZCA9IDE6biwgbG5DVlI9MCwgbG5DVlJfbG93ZXI9MCwgbG5DVlJfdXBwZXI9MCwgCiAgICAgICAgICAgbG5DVlJfc2U9MCwgbG5WUj0wLCBsblZSX2xvd2VyPTAsIGxuVlJfdXBwZXI9MCwgCiAgICAgICAgICAgbG5WUl9zZT0wLCBsblJSPTAsIGxuUlJfbG93ZXI9MCwgbG5SUl91cHBlcj0wLCBsblJSX3NlPTAsIHNhbXBsZVNpemU9MCwgdHJhaXQ9MCkKCmZvciAodCBpbiAxOm4pIHsKICB0cnlDYXRjaCgKICAgIHsKICAgICAgcmVzdWx0cyA8LSBkYXRhICU+JSAKICAgICAgICBkYXRhX3N1YnNldF9wYXJhbWV0ZXJpZF9pbmRpdmlkdWFsX2J5X2FnZSh0KSAlPiUKICAgICAgICBjYWxjdWxhdGVfcG9wdWxhdGlvbl9zdGF0cygpICU+JQogICAgICAgIGNyZWF0ZV9tZXRhX2FuYWx5c2lzX2VmZmVjdF9zaXplcygpCgogICAgICAjIGxuQ1ZSLCAgbG9nIHJlcHNvbnNlLXJhdGlvIG9mIHRoZSBjb2VmZmljaWVudCBvZiB2YXJpYW5jZQogICAgICBjdnIgPC0gbWV0YWZvcjo6cm1hLm12KHlpID0gZWZmZWN0X3NpemVfQ1ZSLCBWID0gc2FtcGxlX3ZhcmlhbmNlX0NWUiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tID0gbGlzdCh+IDEgfCBzdHJhaW5fbmFtZSwgfiAxIHwgcHJvZHVjdGlvbl9jZW50ZXIsIH4gMSB8IGVyciksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGLCBkYXRhID0gcmVzdWx0cykKCiAgICAgICMgbG5WUiwgY29tcGFyaXNvbiBvZiBzdGFuZGFyZCBkZXZpYXRpb25zCiAgICAgIGN2IDwtIG1ldGFmb3I6OnJtYS5tdih5aSA9IGVmZmVjdF9zaXplX1ZSLCBWID0gc2FtcGxlX3ZhcmlhbmNlX1ZSLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tID0gbGlzdCh+IDEgfCBzdHJhaW5fbmFtZSwgfiAxIHwgcHJvZHVjdGlvbl9jZW50ZXIsIH4gMSB8IGVyciksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbCA9IGxpc3Qob3B0aW1pemVyID0gIm9wdGltIiwgb3B0bWV0aG9kID0gIk5lbGRlci1NZWFkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhpdCA9IDEwMDApLCB2ZXJib3NlID0gRiwgZGF0YSA9IHJlc3VsdHMpCgogICAgICAjIGZvciBtZWFucywgbG5SUgogICAgICBtZWFucyA8LSBtZXRhZm9yOjpybWEubXYoeWkgPSBlZmZlY3Rfc2l6ZV9SUiwgViA9IHNhbXBsZV92YXJpYW5jZV9SUiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20gPSBsaXN0KH4gMSB8IHN0cmFpbl9uYW1lLCB+IDEgfCBwcm9kdWN0aW9uX2NlbnRlciwgfiAxIHwgZXJyKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGLCBkYXRhID0gcmVzdWx0cykKICAgICAgCiAgICAgIGYgPC0gZnVuY3Rpb24oeCkgdW5saXN0KHhbYygiYiIsICJjaS5sYiIsICJjaS51YiIsICJzZSIpXSkKCiAgICAgIHJlc3VsdHNfYWxsdHJhaXRzX2dyb3VwaW5nW3QsIDI6MTRdIDwtIGMoZihjdnIpLCBmKGN2KSwgZihtZWFucyksIG1lYW5zJGspCiAgICAgIHJlc3VsdHNfYWxsdHJhaXRzX2dyb3VwaW5nW3QsIDE1XSA8LSB1bmlxdWUocmVzdWx0cyR0cmFpdCkKICAgIH0sCiAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICAgICAgY2F0KCJFUlJPUiA6IiwgdCwgY29uZGl0aW9uTWVzc2FnZShlKSwgIlxuIikKICAgIH0KICApCn0KYGBgCgotLS0tLS0tLQoqKlJFVklFVyoqOiBUaGUgYWJvdmUgbG9vcCBnaXZlcyBzb21lIGVycm9ycywgY2FuIHRoZXNlIGJlIGZpeGVkPwoqKkZaKio6IEluIHRoZSBhYm92ZSBmdW5jdGlvbiwgd2UgdXNlICd0cnlDYXRjaCcgYW5kICdjb25kaXRpb25NZXNzYWdlJyB0byBwcmV2ZW50IHRoZSBsb29wIGZyb20gYWJvcnRpbmcgd2hlbiB0aGUgZmlyc3QgZXJyb3IgYXQgcm93IDg0IGlzIHByb2R1Y2VkLgoqKkZaKiogIENvbnZlcmdlbmNlIGluIHRoZSB0d28gbGlzdGVkIG5vbi1jb252ZXJnaW5nIGNhc2VzIGNhbid0IGJlIGFjaGlldmVkIGJ5IHNlbnNpYmx5IHR3ZWFraW5nIChvdGhlciBvcHRpbSBldGMuKS4KKipGWioqICBTaW5jZSB3ZSBvbmx5IGxlYXJuIGFib3V0IG5vbi1jb252ZXJnZW5jZSBpbiB0aGUgbG9vcCwgaXQncyBkaWZmaWN1bHQgdG8gZXhjbHVkZSB0aGUgdHdvIHRyYWl0cyBiZWZvcmVoYW5kLgoqKkZaKiogIFNpbWlsYXJseSwgdGhlIDggdHJhaXRzIHdpdGggdmVyeSBsb3cgdmFyaWF0aW9uICgxNjAsIC4uLiwgMjMxKSBhcmUgaGFyZCB0byBleGNsdWRlIGJlZm9yZS4KKipGWioqICBXYXJuaW5ncyBhcmUgb2s6IGluZGljYXRpbmcgY2FzZXMgd2hlcmUgdmFyaWFuY2UgY29tcG9uZW50cyBhcmUgc2V0IHRvIHplcm8gZHVyaW5nIGxpa2VsaWhvb2Qgb3B0aW1pemF0aW9uLgoKRVJST1IgOiA4NCBPcHRpbWl6ZXIgKG9wdGltKSBkaWQgbm90IGFjaGlldmUgY29udmVyZ2VuY2UgKGNvbnZlcmdlbmNlID0gMTApLiAKRVJST1IgOiAxNTggT3B0aW1pemVyIChvcHRpbSkgZGlkIG5vdCBhY2hpZXZlIGNvbnZlcmdlbmNlIChjb252ZXJnZW5jZSA9IDEwKS4gCkVSUk9SIDogMTYwIE5BL05hTi9JbmYgaW4gJ3knIApFUlJPUiA6IDE2MSBOQS9OYU4vSW5mIGluICd5JyAKRVJST1IgOiAxNjIgTkEvTmFOL0luZiBpbiAneScgCkVSUk9SIDogMTYzIE5BL05hTi9JbmYgaW4gJ3knIApFUlJPUiA6IDE2NSBOQS9OYU4vSW5mIGluICd5JyAKRVJST1IgOiAxNjYgTkEvTmFOL0luZiBpbiAneScgCkVSUk9SIDogMTY4IE5BL05hTi9JbmYgaW4gJ3knCkVSUk9SIDogMjMxIE5BL05hTi9JbmYgaW4gJ3knIAoKCkFsc28gYSBidW5jaCBvZiB3YXJuaW5ncywgYXJlIGFueSBvZiB0aGVzZSBhIGNvbmNlcm4/Cgo+IHdhcm5pbmdzKCkKV2FybmluZyBtZXNzYWdlczoKMTogSW4gbWV0YWZvcjo6cm1hLm12KHlpID0gZWZmZWN0X3NpemVfQ1ZSLCBWID0gc2FtcGxlX3ZhcmlhbmNlX0NWUiwgIC4uLiA6CiAgUm93cyB3aXRoIE5BcyBvbWl0dGVkIGZyb20gbW9kZWwgZml0dGluZy4KLi4uCjEzOiBJbiBtZXRhZm9yOjpybWEubXYoeWkgPSBlZmZlY3Rfc2l6ZV9SUiwgViA9IHNhbXBsZV92YXJpYW5jZV9SUiwgIC4uLiA6CiAgVGhlcmUgYXJlIG91dGNvbWVzIHdpdGggbm9uLXBvc2l0aXZlIHNhbXBsaW5nIHZhcmlhbmNlcy4KMTQ6IEluIG1ldGFmb3I6OnJtYS5tdih5aSA9IGVmZmVjdF9zaXplX1JSLCBWID0gc2FtcGxlX3ZhcmlhbmNlX1JSLCAgLi4uIDoKICAnVicgYXBwZWFycyB0byBiZSBub3QgcG9zaXRpdmUgZGVmaW5pdGUuCjE2OiBJbiBtZXRhZm9yOjpybWEubXYoeWkgPSBlZmZlY3Rfc2l6ZV9DVlIsIFYgPSBzYW1wbGVfdmFyaWFuY2VfQ1ZSLCAgLi4uIDoKICBTaW5nbGUtbGV2ZWwgZmFjdG9yKHMpIGZvdW5kIGluICdyYW5kb20nIGFyZ3VtZW50LiBDb3JyZXNwb25kaW5nICdzaWdtYTInIHZhbHVlKHMpIGZpeGVkIHRvIDAuCi4uLgo1MDogSW4gbWV0YWZvcjo6cm1hLm12KHlpID0gZWZmZWN0X3NpemVfUlIsIFYgPSBzYW1wbGVfdmFyaWFuY2VfUlIsICAuLi4gOgogICdWJyBhcHBlYXJzIHRvIGJlIG5vdCBwb3NpdGl2ZSBkZWZpbml0ZQoKLS0tLS0tCk5vdyB0aGF0IHdlIGhhdmUgYSAicmVzdWx0cyIgdGFibGUgd2l0aCBlYWNoIG9mIHRoZSBtZXRhLWFuYWx5dGljIG1lYW5zIGZvciBhbGwgZWZmZWN0IHNpemVzIG9mIGludGVyZXN0LCB3ZSBjYW4gdXNlIHRoaXMgdGFibGUgYXMgcGFydCBvZiB0aGUgU2hpbnkgQXBwLCB3aGljaCB3aWxsIHRoZW4gYmUgYWJsZSB0byBiYWNrIGNhbGN1bGF0ZSB0aGUgcGVyY2VudGFnZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzIGZvciBtZWFuLCB2YXJpYW5jZSBhbmQgY29lZmZpY2llbnQgb2YgdmFyaWFuY2UuIFdlJ2xsIGV4cG9ydCBhbmQgdXNlIHRoaXMgaW4gdGhlIFNoaW55IEFwcC4gKipOb3RlIHRoYXQgSSBoYXZlIG5vdCBkZWFsdCB3aXRoIGNvbnZlcmdlbmNlIGlzc3VlcyBpbiBzb21lIG9mIHRoZXNlIG1vZGVscywgYW5kIHNvLCB0aGlzIHdpbGwgbmVlZCB0byBiZSBkb25lIGRvd24gdGhlIHJvYWQqKgoKKE5vdGUgU3VzaSAzMS83LzIwMTk6IFRoaXMgZGF0YXNldCBjb250YWlucyBkdWJsaWNhdGVkIHZhbHVlcywgcGx1cyBubyBpbmZvIG9uIHdoYXQgdGhlICJ0cmFpdHMiIG1lYW4uIEkgd2lsbCBjaGFuZ2UgRGFuIE4ncyB0byBvbmUgZnVydGhlciBiZWx3bywgdGhhdCBoYXZlIGJlZW4gY2xlYW5lZCB1cCBhbHJlYWR5CkZJTEUgVE8gVVNFOiBNRVRBQ09NQk8gKGFyb3VuZCBsaW5lIDUwMCkpCgojIyMgTWVyZ2luZyBkYXRhc2V0cyAmIHJlbW92YWwgb2Ygbm9uLWNvbnZlcmdlZCB0cmFpdHMKClByb2NlZHVyZSBuYW1lcywgZ3JvdXBpbmcgdmFyaWFibGVzIGV0Yy4gYXJlIG1lcmdlZCBiYWNrIHRvZ2V0aGVyIHdpdGggdGhlIHJlc3VsdHMgZnJvbSB0aGUgbWV0YWZvciBhbmFseXNpcyBhYm92ZS4gVGhpcyByZXF1aXJlcyBsb2FkaW5nIG9mIGFub3RoZXIgZXhjZWwgc2hlZXQsICJwcm9jZWR1cmVzLmNzdiIKIAoKYGBge3J9CnJlc3VsdHNfYWxsdHJhaXRzX2dyb3VwaW5nMiA8LSAKICByZXN1bHRzX2FsbHRyYWl0c19ncm91cGluZyAlPiUgCiAgbGVmdF9qb2luKGJ5PSJpZCIsCiAgICAgICAgICAgICBkYXRhICU+JSBzZWxlY3QoaWQsIHBhcmFtZXRlcl9ncm91cCwgcHJvY2VkdXJlID0gcHJvY2VkdXJlX25hbWUsIHByb2NlZHVyZV9uYW1lLCBwYXJhbWV0ZXJfbmFtZSkgJT4lICNzdXNpOiBjaGVjayBwYXJhdGVlciBncm91cAogICAgICAgICAgICAgICMgUkVWSUVXIC0tIHRoaXMgYmV4dCBsaW5lIHJlcGxjaWF0ZXMgcHJlY2lvdXMgY29kZSwgYnV0IHJlbW92ZXMgc29tZSBwcm9jZWR1cmVzLCBpcyB0aGF0IHJpZ2h0PwoJCSAgIyBGWjogTm8uIFRoaXMgY3JlYXRlcyB0aGUgZGF0YSBmcm9tIHRoZSBjb21wbGV0ZSBkYXRhIHNldCAoJ2RhdGEnKSwgd2hpY2ggd2FzIG5vdCBjYXJyaWVkIG92ZXIgaW50byAncmVzdWx0c19hbGx0cmFpdHNfZ3JvdXBpbmcnCgkJICAjIEZaOiBXZSBmaWx0ZXIgZHVwbGljYXRlZCBpZCdzIHRvIGdldCBvbmx5IG9uZSB1bmlxdWUgcm93IHBlciBpZCAoYW5kIHRoZXJlIGlzIG9uZSBpZCBwZXIgcGFyYW1ldGVyX25hbWUpCiAgICAgICAgICAgICAgZmlsdGVyKCFkdXBsaWNhdGVkKGlkKSkKICAgICAgICAgICAgKSAlPiUKICAjIEZaOiBCZWxvdyB3ZSBhZGQgJ3Byb2NlZHVyZScgKGZyb20gdGhlIHByZXZpb3VzbHkgbG9hZGVkICdwcm9jZWR1cmVzLmNzdicpIGFzIGEgdmFyaWFibGUKICBsZWZ0X2pvaW4oYnk9InByb2NlZHVyZSIsIAogICAgICAgICAgICBwcm9jZWR1cmVzICU+JSBkaXN0aW5jdCgpCiAgICAgICAgICAgICkKICAKCm4gPC0gbGVuZ3RoKHVuaXF1ZShyZXN1bHRzX2FsbHRyYWl0c19ncm91cGluZzIkcGFyYW1ldGVyX25hbWUpKSAjIDIzMgpgYGAKClJlbW92YWwgb2YgdHJhaXRzIHRoYXQgZGlkIG5vdCBhY2hpZXZlIGNvbnZlcmdlbmNlLCBhcmUgbm9uc2Vuc2ljYWwgZm9yIGFuYWx5c2lzIG9mIHZhcmlhbmNlIChzdWNoIGFzIHRyYWl0cyB0aGF0IHNob3cgdmFyaWF0aW9uLCBzdWNoIGFzIG51bWJlciBvZiByaWJzLCBkaWdpdHMsIGV0YykuIDE0IHRyYWl0cyBmcm9tIHRoZSBvcmlnaW5hbGx5IDIzMiB0aGF0IGhhZCBiZWVuIGluY2x1ZGVkIGFyZSByZW1vdmVkLgoKKipSZXZpZXcqKjogSG93IGRpZCB3ZSBkZXRlcm1pbmUgdGhpcyB0aGUgb25lcyB3aXRoIHByb2JsZW1zPyAKKipGWioqOiBJbiBhZGRpdGlvbiB0byB0aGUgc2VudGVuY2Ugb25lIGxpbmUgYWJvdmUsIHRvIGRvOiBhZGQgaW5mb3JtYXRpb24gYWJvdXQgY2F1c2Ugb2YgZXhjbHVzaW9uICggMS4gbm9uLWNvbnZlcmdlbmNlIG9mIG1ldGFmb3IgbW9kZWxzLCBvciAyLiBubyB2YXJpYXRpb24vbm9uc2Vuc2ljYWwpOyByZWZlcmVuY2UgdHJhaXRzIHRvIGJlIGV4Y2x1ZGVkIGJ5IHRyYWl0IG5hbWUgKG5vdCBpZCBudW1iZXIpCioqRloqKjogZXhjbHVkZWQgYmVjYXVzZSBvZiBub24tY29udmVyZ2VuY2U6IDg0LCAxNTgKKipGWioqOiBleGNsdWRlZCBiZWNhdXNlIG5vIHZhcmlhdGlvbi9ub25zZW5zaWNhbDogMTQ0LCAxNTgsIDE2MCwuLi4gCmBgYHtyfQoKI0ZaIGRlbGV0ZSMgaGFzX3Byb2JsZW1zIDwtIGMoODQsIDE0NCwgMTU4LCAxNjAsIDE2MSwgMTYyLCAxNjMsIDE2NSwgMTY2LCAxNjcsIDE2OCwgMjIxLCAyMjIsIDIzMSkKI0ZaIGRlbGV0ZSMgbWV0YV9jbGVhbiA8LSByZXN1bHRzX2FsbHRyYWl0c19ncm91cGluZzIgJT4lIGZpbHRlcighaWQgJWluJSBoYXNfcHJvYmxlbXMpCiNGWiBkZWxldGUjIG1ldGFfcHJvYmxlbSA8LSByZXN1bHRzX2FsbHRyYWl0c19ncm91cGluZzIgJT4lIGZpbHRlcihpZCAlaW4lIGhhc19wcm9ibGVtcykKCiMqKkZaKio6IFdlIGV4Y2x1ZGUgMTQgcGFyYW1ldGVyIG5hbWVzIGZvciB3aGljaCBtZXRhZm9yIG1vZGVscyBkaWRuJ3QgY29udmVyZ2UgKCJkcCB0IGNlbGxzIiwgIm16YiAoY2QyMS8zNSBoaWdoKSIpLCBhbmQgb2YgcGFyYW1ldGVycyB0aGF0IGRvbid0IGhhcmJvdXIgZW5vdWdoIHZhcmlhdGlvbgptZXRhX2NsZWFuIDwtIHJlc3VsdHNfYWxsdHJhaXRzX2dyb3VwaW5nMiAlPiUgCgkgIGZpbHRlcighcGFyYW1ldGVyX25hbWUgJWluJSBjKCJkcCB0IGNlbGxzIiwgIm16YiAoY2QyMS8zNSBoaWdoKSIsICJudW1iZXIgb2YgY2F1ZGFsIHZlcnRlYnJhZSIsIAoJICAibnVtYmVyIG9mIGNlcnZpY2FsIHZlcnRlYnJhZSIsICJudW1iZXIgb2YgZGlnaXRzIiwgIm51bWJlciBvZiBsdW1iYXIgdmVydGVicmFlIiwgIm51bWJlciBvZiBwZWx2aWMgdmVydGVicmFlIiwgIm51bWJlciBvZiByaWJzIGxlZnQiLCAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgIm51bWJlciBvZiByaWJzIHJpZ2h0IiwgIm51bWJlciBvZiBzaWduYWxzIiwgIm51bWJlciBvZiB0aG9yYWNpYyB2ZXJ0ZWJyYWUiLCAidG90YWwgbnVtYmVyIG9mIGFjcXVpcmVkIGV2ZW50cyBpbiBwYW5lbCBhIiwKICAgICAgICAidG90YWwgbnVtYmVyIG9mIGFjcXVpcmVkIGV2ZW50cyBpbiBwYW5lbCBiIiwgIndob2xlIGFyZW5hIHBlcm1hbmVuY2UiKSkKCmBgYApgYGAKCioqUmV2ZWl3Kio6IGNoZWNrIGFnYWluc3Qgb2xkIHNjcmlwdCAtLSBpZGVudGljYWwsIHJlbW92ZSBvbmNlIGZpeGVkCgpgYGB7ciwgZXZhbD1GQUxTRX0KbWV0YV9jbGVhbi50ZXN0IDwtIHJlYWRSRFMoIi4uL21ldGFfY2xlYW4udGVzdC5yZHMiKSAgI0ZaIGNvbW1lbnQ6IGRvZXNuJ3Qgd29yayBmb3IgbWUuICcuLi8nIGlzIGZvciB0aGUgZ2l0aHViIGxvY2F0aW9uPwphbGwuZXF1YWwobWV0YV9jbGVhbiwgbWV0YV9jbGVhbi50ZXN0KQphbGwuZXF1YWwobWV0YV9jbGVhbiAlPiUgc2VsZWN0KC1wYXJhbWV0ZXJfZ3JvdXApLCBtZXRhX2NsZWFuLnRlc3QgJT4lIG11dGF0ZShpZD1hcy5pbnRlZ2VyKGlkKSwgR3JvdXBpbmdUZXJtID0gYXMuY2hhcmFjdGVyKEdyb3VwaW5nVGVybSkpKQpgYGAKCgoKIyMgTWV0YS1hbmFseXNpcywgUGhhc2UgMjogbm9uLWluZGVwZW5kZW50IHRyYWl0cwojIyMgRGVhbGluZyB3aXRoIENvcnJlbGF0ZWQgUGFyYW1ldGVycywgcHJlcGFyYXRpb24KClRoaXMgZGF0YXNldCBjb250YWluZWQgYSBudW1iZXIgb2YgaGlnaGx5IGNvcnJlbGF0ZWQgdHJhaXRzLCBzdWNoIGFzIGRpZmZlcmVudCBraW5kcyBvZiBjZWxsIGNvdW50cyAoZm9yIGV4YW1wbGUsIGhpZXJhcmNoaWNhbCBwYXJhbWV0ZXJpemF0aW9uIHdpdGhpbiBpbW11bm9sb2dpY2FsIGFzc2F5cykuIEFzIHRob3NlIGRhdGEtcG9pbnRzIGFyZSBub3QgaW5kZXBlbmRlbnQgb2YgZWFjaCBvdGhlciwgIHdlIGNvbmR1Y3RlZCBhIG1ldGEgYW5hbHlzZXMgb24gdGhlc2UgY29ycmVsYXRlZCBwYXJhbWV0ZXJzIHRvIGNvbGxhcHNlIHRoZSBudW1iZXIgb2YgbGV2ZWxzLgoKIyMjIyBDb2xsYXBzaW5nIGFuZCBtZXJnaW5nIGNvcnJlbGF0ZWQgcGFyYW1ldGVycwoKSGVyZSB3ZSBkb3VibGUgY2hlY2sgbnVtYmVycyBvZiB0cmFpdCBwYXJhbWV0ZXJzIGluIHRoZSBkYXRhc2V0CgpgYGB7cn0KCm1ldGExIDwtIG1ldGFfY2xlYW4KbGVuZ3RoKHVuaXF1ZShtZXRhMSRwcm9jZWR1cmUpKSAjMTgKbGVuZ3RoKHVuaXF1ZShtZXRhMSRHcm91cGluZ1Rlcm0pKSAjOQojIFJldmlldzogbmV4dCBsaW5lIG5vdyAxNTUgbm90IDE0OCAjRlogY29tbWVudDogc3RpbGwgMTQ4IGZvciBtZS4KbGVuZ3RoKHVuaXF1ZShtZXRhMSRwYXJhbWV0ZXJfZ3JvdXApKSAjIDE0OCBsZXZlbHMuIFRvIGJlIHVzZWQgYXMgZ3JvdXBpbmcgZmFjdG9yIGZvciBtZXRhLW1ldGEgYW5hbHlzaXMgLyBjb2xsYXBzaW5nIGRvd24gYmFzZWQgb24gdGhpbmdzIHRoYXQgYXJlIGNsYXNzaWZpZWQgaWRlbnRpY2FsbHkgaW4gInBhcmFtZXRlcl9ncm91cCIgYnV0IGhhdmUgZGlmZmVyZW50ICJwYXJhbWV0ZXJfbmFtZSIKbGVuZ3RoKHVuaXF1ZShtZXRhMSRwYXJhbWV0ZXJfbmFtZSkpICMyMTgKYGBgCgojIyMjIENvdW50IG9mIG51bWJlciBvZiBwYXJhbWV0ZXIgbmFtZXMgKGNvcnJlbGF0ZWQgc3ViLXRyYWl0cykgaW4gZWFjaCBwYXJhbWV0ZXIgZ3JvdXAgKHBhcl9ncm91cF9zaXplKSAKClRoaXMgc2VydmVzIHRvIGlkZW50aWZ5IGFuZCBzZXBhcmF0ZSB0aGUgdHJhaXRzIHRoYXQgYXJlIGNvcnJlbGF0ZWQgZnJvbSB0aGUgZnVsbCBkYXRhc2V0IHRoYXQgY2FuIGJlIHByb2Nlc3NlZCBhcyBpcy4gSWYgdGhlIHNhbXBsZSBzaXplIChuKSBmb3IgYSBnaXZlbiAicGFyYW1ldGVyIGdyb3VwIiBlcXVhbHMgMSwgdGhlIHRyYWl0IGlzIHVuaXF1ZSBhbmQgdW5jb3JyZWxhdGVkLiBBbGwgaW5zdGFuY2VzLCB3aGVyZSB0aGVyZSBhcmUgMiBvciBtb3JlIHRyYWl0cyBhc3NvY2lhdGVkIHdpdGggdGhlIHNhbWUgIHBhcmFtZXRlciBncm91cCAoOTAgY2FzZXMpLCBhcmUgc2VsZWN0ZWQgZm9yIGEgIm1pbmktbWV0YSBhbmFseXNpcyIsIHdoaWNoIHJlbW92ZXMgdGhlIGlzc3VlIG9mIGNvcnJlbGF0aW9uLgoKYGBge3J9CgprYWJsZShjYmluZChtZXRhMSAlPiUgY291bnQocGFyYW1ldGVyX2dyb3VwKSkpICU+JQogIGthYmxlX3N0eWxpbmcoKSAlPiUKICBzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiLCBoZWlnaHQgPSAiMjAwcHgiKQpgYGAKCmBgYHtyfQptZXRhMV9zdWIgPC0gbWV0YTEgJT4lCiAgIyBhZGQgc3VtbWFyeSBvZiBudW1iZXIgb2YgcGFyYW1ldGVyIG5hbWVzIGluIGVhY2ggcGFyYW1ldGVyIGdyb3VwCiAgZ3JvdXBfYnkocGFyYW1ldGVyX2dyb3VwKSAlPiUKICBtdXRhdGUocGFyX2dyb3VwX3NpemUgPSBsZW5ndGgodW5pcXVlKHBhcmFtZXRlcl9uYW1lKSksIAogICAgICAgICBzYW1wbGVTaXplID0gYXMubnVtZXJpYyhzYW1wbGVTaXplKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgIyBDcmVhdGUgc3Vic2V0cyB3aXRoID4gMSBjb3VudCAocGFyX2dyb3VwX3NpemUgPiAxKQogIGZpbHRlcihwYXJfZ3JvdXBfc2l6ZSA+IDEpICMgOTAgb2JzZXJ2YXRpb25zCmBgYAoKIyMjIyBNZXRhLWFuYWx5c2VzIG9uIGNvcnJlbGF0ZWQgKHN1Yi0pdHJhaXRzLCB1c2luZyByb2J1bWV0YWAgClRoZSBzdWJzZXQgb2YgdGhlIGRhdGEgaXMgcHJlcGFyZWQgKG5lc3RlZCksIGFuZCBpbiB0aGlzIGZpcnN0IHN0ZXAgdGhlIG1vZGVsIG9mIHRoZSBtZXRhIGFuYWx5c2lzIGVmZmVjdCBzaXplcyBhcmUgY2FsY3VsYXRlZAoKYGBge3J9CgoKbWV0YTFiIDwtCiAgbWV0YTEgJT4lCiAgZ3JvdXBfYnkocGFyYW1ldGVyX2dyb3VwKSAlPiUgCiAgc3VtbWFyaXplKHBhcl9ncm91cF9zaXplID0gbGVuZ3RoKHVuaXF1ZShwYXJhbWV0ZXJfbmFtZSwgbmEucm0gPSBUUlVFKSkpCiN0aGlzIGdpdmVzIGEgc3VtbWFyeSBvZiBudW1iZXIgb2YgcGFyYW1ldGVyIG5hbWVzIGluIGVhY2ggcGFyYW1ldGVyIGdyb3VwLCBub3cgaXQgbmVlZWRzIHRvIGdldCBtZXJnZWQgaXQgYmFjayB0b2dldGhlcgoKCm1ldGExJHBhcl9ncm91cF9zaXplIDwtIG1ldGExYiRwYXJfZ3JvdXBfc2l6ZVttYXRjaChtZXRhMSRwYXJhbWV0ZXJfZ3JvdXAsIG1ldGExYiRwYXJhbWV0ZXJfZ3JvdXApXQoKIyBDcmVhdGUgc3Vic2V0cyB3aXRoID4gMSBjb3VudCAocGFyX2dyb3VwX3NpemUgPiAxKSAKCm1ldGExX3N1YiA8LSBzdWJzZXQobWV0YTEscGFyX2dyb3VwX3NpemUgPjEpICMgOTAgb2JzZXJ2YXRpb25zICAgCm1ldGExX3N1YiRzYW1wbGVTaXplIDwtIGFzLm51bWVyaWMobWV0YTFfc3ViJHNhbXBsZVNpemUpCgojIG5lc3RpbmcKbl9jb3VudCA8LSBtZXRhMV9zdWIgJT4lCiAgZ3JvdXBfYnkocGFyYW1ldGVyX2dyb3VwKSAlPiUKICBtdXRhdGUocmF3X04gPSBzdW0oc2FtcGxlU2l6ZSkpICU+JQogIG5lc3QoKSAlPiUKICB1bmdyb3VwKCkKCm1vZGVsX2NvdW50IDwtIG5fY291bnQgJT4lCiAgbXV0YXRlKAogICAgbW9kZWxfbG5SUiA9IG1hcChkYXRhLCB+IHJvYnUoLngkbG5SUiB+IDEsIGRhdGEgPSAueCwgc3R1ZHludW0gPSAueCRpZCwgbW9kZWx3ZWlnaHRzID0gYygiQ09SUiIpLCByaG8gPSAwLjgsIHNtYWxsID0gVFJVRSwgdmFyLmVmZi5zaXplID0gKC54JGxuUlJfc2UpXjIpKSwKICAgIG1vZGVsX2xuVlIgPSBtYXAoZGF0YSwgfiByb2J1KC54JGxuVlIgfiAxLCBkYXRhID0gLngsIHN0dWR5bnVtID0gLngkaWQsIG1vZGVsd2VpZ2h0cyA9IGMoIkNPUlIiKSwgcmhvID0gMC44LCBzbWFsbCA9IFRSVUUsIHZhci5lZmYuc2l6ZSA9ICgueCRsblZSX3NlKV4yKSksCiAgICBtb2RlbF9sbkNWUiA9IG1hcChkYXRhLCB+IHJvYnUoLngkbG5DVlIgfiAxLCBkYXRhID0gLngsIHN0dWR5bnVtID0gLngkaWQsIG1vZGVsd2VpZ2h0cyA9IGMoIkNPUlIiKSwgcmhvID0gMC44LCBzbWFsbCA9IFRSVUUsIHZhci5lZmYuc2l6ZSA9ICgueCRsbkNWUl9zZSleMikpCiAgKQpgYGAKCkV4dHJhY3QgYW5kIHNhdmUgcGFyYW1ldGVyIGVzdGltYXRlczoKRnVuY3Rpb24gdG8gY29sbGVjdCB0aGUgb3V0Y29tZXMgb2YgdGhlICJtaW5pIiBtZXRhIGFuYWx5c2lzCgpgYGB7cn0KY291bnRfZnVuIDwtIGZ1bmN0aW9uKG1vZF9zdWIpIHsKICByZXR1cm4oYyhtb2Rfc3ViJHJlZ190YWJsZSRiLnIsIG1vZF9zdWIkcmVnX3RhYmxlJENJLkwsIG1vZF9zdWIkcmVnX3RhYmxlJENJLlUsIG1vZF9zdWIkcmVnX3RhYmxlJFNFKSkKfSAjIGVzdGltYXRlLCBsb3dlciBjaSwgdXBwZXIgY2ksIFNFCmBgYAoKRXh0cmFjdGlvbiBvZiB2YWx1ZXMgY3JlYXRlZCBkdXJpbmcgTWV0YSBhbmFseXNpcyB1c2luZyByb2J1IG1ldGE6CgpgYGB7cn0Kcm9idXN1Yl9SUiA8LSBtb2RlbF9jb3VudCAlPiUKICB0cmFuc211dGUocGFyYW1ldGVyX2dyb3VwLCBlc3RpbWF0ZWxuUlIgPSBtYXAobW9kZWxfbG5SUiwgY291bnRfZnVuKSkgJT4lCiAgbXV0YXRlKHIgPSBtYXAoZXN0aW1hdGVsblJSLCB+IGRhdGEuZnJhbWUodCguKSkpKSAlPiUKICB1bm5lc3QocikgJT4lCiAgc2VsZWN0KC1lc3RpbWF0ZWxuUlIpICU+JQogIHB1cnJyOjpzZXRfbmFtZXMoYygicGFyYW1ldGVyX2dyb3VwIiwgImxuUlIiLCAibG5SUl9sb3dlciIsICJsblJSX3VwcGVyIiwgImxuUlJfc2UiKSkKCnJvYnVzdWJfQ1ZSIDwtIG1vZGVsX2NvdW50ICU+JQogIHRyYW5zbXV0ZShwYXJhbWV0ZXJfZ3JvdXAsIGVzdGltYXRlbG5DVlIgPSBtYXAobW9kZWxfbG5DVlIsIGNvdW50X2Z1bikpICU+JQogIG11dGF0ZShyID0gbWFwKGVzdGltYXRlbG5DVlIsIH4gZGF0YS5mcmFtZSh0KC4pKSkpICU+JQogIHVubmVzdChyKSAlPiUKICBzZWxlY3QoLWVzdGltYXRlbG5DVlIpICU+JQogIHB1cnJyOjpzZXRfbmFtZXMoYygicGFyYW1ldGVyX2dyb3VwIiwgImxuQ1ZSIiwgImxuQ1ZSX2xvd2VyIiwgImxuQ1ZSX3VwcGVyIiwgImxuQ1ZSX3NlIikpCgpyb2J1c3ViX1ZSIDwtIG1vZGVsX2NvdW50ICU+JQogIHRyYW5zbXV0ZShwYXJhbWV0ZXJfZ3JvdXAsIGVzdGltYXRlbG5WUiA9IG1hcChtb2RlbF9sblZSLCBjb3VudF9mdW4pKSAlPiUKICBtdXRhdGUociA9IG1hcChlc3RpbWF0ZWxuVlIsIH4gZGF0YS5mcmFtZSh0KC4pKSkpICU+JQogIHVubmVzdChyKSAlPiUKICBzZWxlY3QoLWVzdGltYXRlbG5WUikgJT4lCiAgcHVycnI6OnNldF9uYW1lcyhjKCJwYXJhbWV0ZXJfZ3JvdXAiLCAibG5WUiIsICJsblZSX2xvd2VyIiwgImxuVlJfdXBwZXIiLCAibG5WUl9zZSIpKQoKcm9idV9hbGwgPC0gZnVsbF9qb2luKHJvYnVzdWJfQ1ZSLCByb2J1c3ViX1ZSKSAlPiUgZnVsbF9qb2luKC4sIHJvYnVzdWJfUlIpCmBgYAoKYGBge3J9CmthYmxlKGNiaW5kKHJvYnVfYWxsLCByb2J1X2FsbCkpICU+JQogIGthYmxlX3N0eWxpbmcoKSAlPiUKICBzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiLCBoZWlnaHQgPSAiMjAwcHgiKQpgYGAKCk1lcmdlIHRoZSB0d28gZGF0YSBzZXRzICh0aGUgbmV3IFtyb2J1X2FsbF0gYW5kIHRoZSBpbml0aWFsIFt1bmNvcnJlbGF0ZWQgc3ViLXRyYWl0cyB3aXRoIGNvdW50ID0gMV0pIAoKYGBge3J9Cm1ldGFfYWxsIDwtIG1ldGExICU+JQogIGZpbHRlcihwYXJfZ3JvdXBfc2l6ZSA9PSAxKSAlPiUKICBhc190aWJibGUoKQojIHN0cihtZXRhX2FsbCkKIyBzdHIocm9idV9hbGwpCiMgd2hpY2goaXMubmEobWF0Y2gobmFtZXMobWV0YV9hbGwpLG5hbWVzKHJvYnVfYWxsKSkpKSAgIyBjaGVjawpgYGAKCiMjIyMgQ29tYmluZSBkYXRhIAoKYGBge3J9CiMgU3RlcDEgKGNvbHVtbnMgYXJlIG1hdGNoZWQgYnkgbmFtZSAoaW4gb3VyIGNhc2UsICdwYXJhbWV0ZXJfZ3JvdXAnKSwgYW5kIGFueSBtaXNzaW5nIGNvbHVtbnMgd2lsbCBiZSBmaWxsZWQgd2l0aCBOQSkgI0ZaIGFkZGVkIGV4cGxhbmF0aW9uIG9mIGJpYmRfcm93cwpjb21iaW5lZG1ldGEgPC0gYmluZF9yb3dzKHJvYnVfYWxsLCBtZXRhX2FsbCkKIyBnbGltcHNlKGNvbWJpbmVkbWV0YSkKCiMgU3RlcHMgMiYzIChhZGQgaW5mb3JtYXRpb24gYWJvdXQgbnVtYmVyIG9mIHRyYWl0cyBpbiBhIHBhcmFtZXRlciBncm91cCwgcHJvY2VkdXJlLCBhbmQgZ3JvdXBpbmcgdGVybSkgI0ZaIGFkZGVkIGV4cGFsbmF0aW9uIGluIGJyYWNrZXRzCm1ldGFjb21ibyA8LSBjb21iaW5lZG1ldGEKbWV0YWNvbWJvJGNvdW50cyA8LSBtZXRhMSRwYXJfZ3JvdXBfc2l6ZVttYXRjaChtZXRhY29tYm8kcGFyYW1ldGVyX2dyb3VwLCBtZXRhMSRwYXJhbWV0ZXJfZ3JvdXApXSAKbWV0YWNvbWJvJHByb2NlZHVyZTIgPC0gbWV0YTEkcHJvY2VkdXJlW21hdGNoKG1ldGFjb21ibyRwYXJhbWV0ZXJfZ3JvdXAsIG1ldGExJHBhcmFtZXRlcl9ncm91cCldCm1ldGFjb21ibyRHcm91cGluZ1Rlcm0yIDwtIG1ldGExJEdyb3VwaW5nVGVybVttYXRjaChtZXRhY29tYm8kcGFyYW1ldGVyX2dyb3VwLCBtZXRhMSRwYXJhbWV0ZXJfZ3JvdXApXQoKa2FibGUoY2JpbmQobWV0YWNvbWJvLCBtZXRhY29tYm8pKSAlPiUKICBrYWJsZV9zdHlsaW5nKCkgJT4lCiAgc2Nyb2xsX2JveCh3aWR0aCA9ICIxMDAlIiwgaGVpZ2h0ID0gIjIwMHB4IikKYGBgCgpDbGVhbi11cCwgcmVvcmRlciwgYW5kIHJlbmFtZSAKCmBgYHtyfQptZXRhY29tYm8gPC0gbWV0YWNvbWJvWywgYygxLCAyMToyMywgMjoxMyldICMgU1VTSSBDSEFOR0UgVE8gTkFNRVMhISEKbmFtZXMobWV0YWNvbWJvKVszXSA8LSAicHJvY2VkdXJlIiAjY2hhbmdlICIzIiB0byBuYW1lCm5hbWVzKG1ldGFjb21ibylbNF0gPC0gIkdyb3VwaW5nVGVybSIgI2NoYW5nZSAiNCIgdG8gbmFtZQoKIyBRdWljayBwcmUtY2hlY2sgYmVmb3JlIGRvaW5nIHBsb3RzCgptZXRhY29tYm8gJT4lCiAgZ3JvdXBfYnkoR3JvdXBpbmdUZXJtKSAlPiUKICBkcGx5cjo6c3VtbWFyaXplKE1lYW5DVlIgPSBtZWFuKGxuQ1ZSKSwgTWVhblZSID0gbWVhbihsblZSKSwgTWVhblJSID0gbWVhbihsblJSKSkKCmBgYAoKCmBgYHtyfQojIFNISU5ZIEFQUCAjIE5vdyB0aGF0IHdlIGhhdmUgYSBjb3JyZWN0ZWQgInJlc3VsdHMiIHRhYmxlIHdpdGggZWFjaCBvZiB0aGUgbWV0YS1hbmFseXRpYyBtZWFucyBmb3IgYWxsIGVmZmVjdCBzaXplcyBvZiBpbnRlcmVzdCwgd2UgY2FuIHVzZSB0aGlzIHRhYmxlIGFzIHBhcnQgb2YgdGhlIFNoaW55IEFwcCwgd2hpY2ggd2lsbCB0aGVuIGJlIGFibGUgdG8gYmFjayBjYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2UgZGlmZmVyZW5jZXMgYmV0d2VlbiBtYWxlcyBhbmQgZmVtYWxlcyBmb3IgbWVhbiwgdmFyaWFuY2UgYW5kIGNvZWZmaWNpZW50IG9mIHZhcmlhbmNlLiBXZSdsbCBleHBvcnQgYW5kIHVzZSB0aGlzIGluIHRoZSBTaGlueSBBcHAuICoqTm90ZSB0aGF0IEkgaGF2ZSBub3QgZGVhbHQgd2l0aCBjb252ZXJnZW5jZSBpc3N1ZXMgaW4gc29tZSBvZiB0aGVzZSBtb2RlbHMsIGFuZCBzbywgdGhpcyB3aWxsIG5lZWQgdG8gYmUgZG9uZSBkb3duIHRoZSByb2FkKioKCiMjIE5vdGUgU3VzaSAzMS83LzIwMTk6IFRoaXMgaGFzIGJlZW4gY2xlYW5lZCB1cCBhbHJlYWR5CiMgRklMRSBUTyBVU0U6IE1FVEFDT01CTwojIyMgbm90ZTogdG8gdXNlCgojIHRyYWl0X21ldGFfcmVzdWx0cyA8LSB3cml0ZS5jc3YobWV0YWNvbWJvLCBmaWxlID0gImV4cG9ydC90cmFpdF9tZXRhX3Jlc3VsdHMuY3N2IikKYGBgCgojIyBNZXRhLWFuYWx5c2lzLCBQaGFzZSAzOiBTZWNvbmQtb3JkZXIgbWV0YSBhbmFseXNpcyBmb3IgZnVuY3Rpb25hbCBncm91cHMKIyMjIyBQZXJmb3JtIG1ldGEtYW5hbHlzZXMgKDMgZm9yIGVhY2ggb2YgdGhlIDkgZ3JvdXBpbmcgdGVybXM6IGxuQ1ZSLCBsblZSLCBsblJSKSAKVGhpcyBpcyB0aGUgZnVsbCByZXN1bHQgZGF0YXNldAoKYGBge3J9CgprYWJsZShjYmluZChtZXRhY29tYm8sIG1ldGFjb21ibykpICU+JQogIGthYmxlX3N0eWxpbmcoKSAlPiUKICBzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiLCBoZWlnaHQgPSAiMjAwcHgiKQpgYGAKCiMjIyMgUHJlcGFyZSBkYXRhCk5lc3RpbmcsIGNhbGN1bGF0aW5nIHRoZSBudW1iZXIgb2YgcGFyYW1ldGVycyB3aXRoaW4gZWFjaCBncm91cGluZyB0ZXJtLCBhbmQgcnVubmluZyB0aGUgbWV0YS1hbmFseXNpcwoKYGBge3J9Cm1ldGFjb21ib19maW5hbCA8LSBtZXRhY29tYm8gJT4lCiAgZ3JvdXBfYnkoR3JvdXBpbmdUZXJtKSAlPiUKI0ZaIGNvbW1lbnQ6IGNoYW5nZWQgJ25lc3QnIHRvICduZXN0X2xlZ2FjeScgdG8ga2VlcCBvbGQgc3ludGF4L2Z1bmN0aW9uYWxpdHkKICBuZXN0X2xlZ2FjeSgpCgoKIyAqKmNhbGN1bGF0ZSBudW1iZXIgb2YgcGFyYW1ldGVycyBwZXIgZ3JvdXBpbmcgdGVybQoKbWV0YWNvbWJvX2ZpbmFsIDwtIG1ldGFjb21ib19maW5hbCAlPiUgbXV0YXRlKHBhcmFfcGVyX0dyb3VwaW5nVGVybSA9IG1hcF9kYmwoZGF0YSwgbnJvdykpCgojIEZvciBhbGwgZ3JvdXBpbmcgdGVybXMKbWV0YWNvbWJvX2ZpbmFsX2FsbCA8LSBtZXRhY29tYm8gJT4lCiNGWiBjb21tZW50OiBjaGFuZ2VkICduZXN0JyB0byAnbmVzdF9sZWdhY3knIHRvIGtlZXAgb2xkIHN5bnRheC9mdW5jdGlvbmFsaXR5CiAgbmVzdF9sZWdhY3koKQoKIyAqKkZpbmFsIGZpeGVkIGVmZmVjdHMgbWV0YS1hbmFseXNlcyB3aXRoaW4gZ3JvdXBpbmcgdGVybXMsIHdpdGggU0Ugb2YgdGhlIGVzdGltYXRlCgpvdmVyYWxsMSA8LSBtZXRhY29tYm9fZmluYWwgJT4lCgogIG11dGF0ZSgKICAgIG1vZGVsX2xuQ1ZSID0gbWFwKGRhdGEsIH4gbWV0YWZvcjo6cm1hLnVuaSgKICAgICAgeWkgPSAueCRsbkNWUiwgc2VpID0gKC54JGxuQ1ZSX3VwcGVyIC0gLngkbG5DVlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgICAgY29udHJvbCA9IGxpc3Qob3B0aW1pemVyID0gIm9wdGltIiwgb3B0bWV0aG9kID0gIk5lbGRlci1NZWFkIiwgbWF4aXQgPSAxMDAwKSwgdmVyYm9zZSA9IEYKICAgICkpLAogICAgbW9kZWxfbG5WUiA9IG1hcChkYXRhLCB+IG1ldGFmb3I6OnJtYS51bmkoCiAgICAgIHlpID0gLngkbG5WUiwgc2VpID0gKC54JGxuVlJfdXBwZXIgLSAueCRsblZSX2xvd2VyKSAvICgyICogMS45NiksCiAgICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgICApKSwKICAgIG1vZGVsX2xuUlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgICB5aSA9IC54JGxuUlIsIHNlaSA9ICgueCRsblJSX3VwcGVyIC0gLngkbG5SUl9sb3dlcikgLyAoMiAqIDEuOTYpLAogICAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDApLCB2ZXJib3NlID0gRgogICAgKSkKICApCgojICoqRmluYWwgZml4ZWQgZWZmZWN0cyBtZXRhLWFuYWx5c2VzIEFDUk9TUyBncm91cGluZyB0ZXJtcywgd2l0aCBTRSBvZiB0aGUgZXN0aW1hdGUKCm92ZXJhbGxfYWxsMSA8LSBtZXRhY29tYm9fZmluYWxfYWxsICU+JQoKICBtdXRhdGUoCiAgICBtb2RlbF9sbkNWUiA9IG1hcChkYXRhLCB+IG1ldGFmb3I6OnJtYS51bmkoCiAgICAgIHlpID0gLngkbG5DVlIsIHNlaSA9ICgueCRsbkNWUl91cHBlciAtIC54JGxuQ1ZSX2xvd2VyKSAvICgyICogMS45NiksCiAgICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgICApKSwKICAgIG1vZGVsX2xuVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgICB5aSA9IC54JGxuVlIsIHNlaSA9ICgueCRsblZSX3VwcGVyIC0gLngkbG5WUl9sb3dlcikgLyAoMiAqIDEuOTYpLAogICAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDApLCB2ZXJib3NlID0gRgogICAgKSksCiAgICBtb2RlbF9sblJSID0gbWFwKGRhdGEsIH4gbWV0YWZvcjo6cm1hLnVuaSgKICAgICAgeWkgPSAueCRsblJSLCBzZWkgPSAoLngkbG5SUl91cHBlciAtIC54JGxuUlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgICAgY29udHJvbCA9IGxpc3Qob3B0aW1pemVyID0gIm9wdGltIiwgb3B0bWV0aG9kID0gIk5lbGRlci1NZWFkIiwgbWF4aXQgPSAxMDAwKSwgdmVyYm9zZSA9IEYKICAgICkpCiAgKQpgYGAKClJlLXN0cnVjdHVyZSBkYXRhIGZvciBlYWNoIGdyb3VwaW5nIHRlcm07IGRlbGV0ZSB1bnVzZWQgdmFyaWFibGVzICAjRlogY29tbWVudDogcmVmZXJlbmNpbmcgb2YgY2VsbHMgYmVsb3cgZG9lc24ndCBkZXBlbmQgb24gcHJldmlvdXMgb3JlZGluZyBvZiB0aGUgZGF0YSwgaS5lLiBvbmx5IGNoYW5nZXMgaWYgb3V0cHV0IHN0cnVjdHVyZSBmcm9tIG1ldGFmb3I6OnJtYS51bmkgY2hhbmdlcwoKYGBge3J9CkJlaGF2aW91ciA8LSBhcy5kYXRhLmZyYW1lKG92ZXJhbGwxICU+JSBmaWx0ZXIoLiwgR3JvdXBpbmdUZXJtID09ICJCZWhhdmlvdXIiKSAlPiUgbXV0YXRlKAogIGxuQ1ZSID0gLltbNF1dW1sxXV0kYiwgbG5DVlJfbG93ZXIgPSAuW1s0XV1bWzFdXSRjaS5sYiwgbG5DVlJfdXBwZXIgPSAuW1s0XV1bWzFdXSRjaS51YiwgbG5DVlJfc2UgPSAuW1s0XV1bWzFdXSRzZSwKICBsblZSID0gLltbNV1dW1sxXV0kYiwgbG5WUl9sb3dlciA9IC5bWzVdXVtbMV1dJGNpLmxiLCBsblZSX3VwcGVyID0gLltbNV1dW1sxXV0kY2kudWIsIGxuVlJfc2UgPSAuW1s1XV1bWzFdXSRzZSwKICBsblJSID0gLltbNl1dW1sxXV0kYiwgbG5SUl9sb3dlciA9IC5bWzZdXVtbMV1dJGNpLmxiLCBsblJSX3VwcGVyID0gLltbNl1dW1sxXV0kY2kudWIsIGxuUlJfc2UgPSAuW1s2XV1bWzFdXSRzZQopKVssIGMoMSwgNzoxOCldCgpJbW11bm9sb2d5IDwtIGFzLmRhdGEuZnJhbWUob3ZlcmFsbDEgJT4lIGZpbHRlciguLCBHcm91cGluZ1Rlcm0gPT0gIkltbXVub2xvZ3kiKSAlPiUgbXV0YXRlKAogIGxuQ1ZSID0gLltbNF1dW1sxXV0kYiwgbG5DVlJfbG93ZXIgPSAuW1s0XV1bWzFdXSRjaS5sYiwgbG5DVlJfdXBwZXIgPSAuW1s0XV1bWzFdXSRjaS51YiwgbG5DVlJfc2UgPSAuW1s0XV1bWzFdXSRzZSwKICBsblZSID0gLltbNV1dW1sxXV0kYiwgbG5WUl9sb3dlciA9IC5bWzVdXVtbMV1dJGNpLmxiLCBsblZSX3VwcGVyID0gLltbNV1dW1sxXV0kY2kudWIsIGxuVlJfc2UgPSAuW1s1XV1bWzFdXSRzZSwKICBsblJSID0gLltbNl1dW1sxXV0kYiwgbG5SUl9sb3dlciA9IC5bWzZdXVtbMV1dJGNpLmxiLCBsblJSX3VwcGVyID0gLltbNl1dW1sxXV0kY2kudWIsIGxuUlJfc2UgPSAuW1s2XV1bWzFdXSRzZQopKVssIGMoMSwgNzoxOCldCgpIZW1hdG9sb2d5IDwtIGFzLmRhdGEuZnJhbWUob3ZlcmFsbDEgJT4lIGZpbHRlciguLCBHcm91cGluZ1Rlcm0gPT0gIkhlbWF0b2xvZ3kiKSAlPiUgbXV0YXRlKAogIGxuQ1ZSID0gLltbNF1dW1sxXV0kYiwgbG5DVlJfbG93ZXIgPSAuW1s0XV1bWzFdXSRjaS5sYiwgbG5DVlJfdXBwZXIgPSAuW1s0XV1bWzFdXSRjaS51YiwgbG5DVlJfc2UgPSAuW1s0XV1bWzFdXSRzZSwKICBsblZSID0gLltbNV1dW1sxXV0kYiwgbG5WUl9sb3dlciA9IC5bWzVdXVtbMV1dJGNpLmxiLCBsblZSX3VwcGVyID0gLltbNV1dW1sxXV0kY2kudWIsIGxuVlJfc2UgPSAuW1s1XV1bWzFdXSRzZSwKICBsblJSID0gLltbNl1dW1sxXV0kYiwgbG5SUl9sb3dlciA9IC5bWzZdXVtbMV1dJGNpLmxiLCBsblJSX3VwcGVyID0gLltbNl1dW1sxXV0kY2kudWIsIGxuUlJfc2UgPSAuW1s2XV1bWzFdXSRzZQopKVssIGMoMSwgNzoxOCldCgpIZWFyaW5nIDwtIGFzLmRhdGEuZnJhbWUob3ZlcmFsbDEgJT4lIGZpbHRlciguLCBHcm91cGluZ1Rlcm0gPT0gIkhlYXJpbmciKSAlPiUgbXV0YXRlKAogIGxuQ1ZSID0gLltbNF1dW1sxXV0kYiwgbG5DVlJfbG93ZXIgPSAuW1s0XV1bWzFdXSRjaS5sYiwgbG5DVlJfdXBwZXIgPSAuW1s0XV1bWzFdXSRjaS51YiwgbG5DVlJfc2UgPSAuW1s0XV1bWzFdXSRzZSwKICBsblZSID0gLltbNV1dW1sxXV0kYiwgbG5WUl9sb3dlciA9IC5bWzVdXVtbMV1dJGNpLmxiLCBsblZSX3VwcGVyID0gLltbNV1dW1sxXV0kY2kudWIsIGxuVlJfc2UgPSAuW1s1XV1bWzFdXSRzZSwKICBsblJSID0gLltbNl1dW1sxXV0kYiwgbG5SUl9sb3dlciA9IC5bWzZdXVtbMV1dJGNpLmxiLCBsblJSX3VwcGVyID0gLltbNl1dW1sxXV0kY2kudWIsIGxuUlJfc2UgPSAuW1s2XV1bWzFdXSRzZQopKVssIGMoMSwgNzoxOCldCgpQaHlzaW9sb2d5IDwtIGFzLmRhdGEuZnJhbWUob3ZlcmFsbDEgJT4lIGZpbHRlciguLCBHcm91cGluZ1Rlcm0gPT0gIlBoeXNpb2xvZ3kiKSAlPiUgbXV0YXRlKAogIGxuQ1ZSID0gLltbNF1dW1sxXV0kYiwgbG5DVlJfbG93ZXIgPSAuW1s0XV1bWzFdXSRjaS5sYiwgbG5DVlJfdXBwZXIgPSAuW1s0XV1bWzFdXSRjaS51YiwgbG5DVlJfc2UgPSAuW1s0XV1bWzFdXSRzZSwKICBsblZSID0gLltbNV1dW1sxXV0kYiwgbG5WUl9sb3dlciA9IC5bWzVdXVtbMV1dJGNpLmxiLCBsblZSX3VwcGVyID0gLltbNV1dW1sxXV0kY2kudWIsIGxuVlJfc2UgPSAuW1s1XV1bWzFdXSRzZSwKICBsblJSID0gLltbNl1dW1sxXV0kYiwgbG5SUl9sb3dlciA9IC5bWzZdXVtbMV1dJGNpLmxiLCBsblJSX3VwcGVyID0gLltbNl1dW1sxXV0kY2kudWIsIGxuUlJfc2UgPSAuW1s2XV1bWzFdXSRzZQopKVssIGMoMSwgNzoxOCldCgpNZXRhYm9saXNtIDwtIGFzLmRhdGEuZnJhbWUob3ZlcmFsbDEgJT4lIGZpbHRlciguLCBHcm91cGluZ1Rlcm0gPT0gIk1ldGFib2xpc20iKSAlPiUgbXV0YXRlKAogIGxuQ1ZSID0gLltbNF1dW1sxXV0kYiwgbG5DVlJfbG93ZXIgPSAuW1s0XV1bWzFdXSRjaS5sYiwgbG5DVlJfdXBwZXIgPSAuW1s0XV1bWzFdXSRjaS51YiwgbG5DVlJfc2UgPSAuW1s0XV1bWzFdXSRzZSwKICBsblZSID0gLltbNV1dW1sxXV0kYiwgbG5WUl9sb3dlciA9IC5bWzVdXVtbMV1dJGNpLmxiLCBsblZSX3VwcGVyID0gLltbNV1dW1sxXV0kY2kudWIsIGxuVlJfc2UgPSAuW1s1XV1bWzFdXSRzZSwKICBsblJSID0gLltbNl1dW1sxXV0kYiwgbG5SUl9sb3dlciA9IC5bWzZdXVtbMV1dJGNpLmxiLCBsblJSX3VwcGVyID0gLltbNl1dW1sxXV0kY2kudWIsIGxuUlJfc2UgPSAuW1s2XV1bWzFdXSRzZQopKVssIGMoMSwgNzoxOCldCgpNb3JwaG9sb2d5IDwtIGFzLmRhdGEuZnJhbWUob3ZlcmFsbDEgJT4lIGZpbHRlciguLCBHcm91cGluZ1Rlcm0gPT0gIk1vcnBob2xvZ3kiKSAlPiUgbXV0YXRlKAogIGxuQ1ZSID0gLltbNF1dW1sxXV0kYiwgbG5DVlJfbG93ZXIgPSAuW1s0XV1bWzFdXSRjaS5sYiwgbG5DVlJfdXBwZXIgPSAuW1s0XV1bWzFdXSRjaS51YiwgbG5DVlJfc2UgPSAuW1s0XV1bWzFdXSRzZSwKICBsblZSID0gLltbNV1dW1sxXV0kYiwgbG5WUl9sb3dlciA9IC5bWzVdXVtbMV1dJGNpLmxiLCBsblZSX3VwcGVyID0gLltbNV1dW1sxXV0kY2kudWIsIGxuVlJfc2UgPSAuW1s1XV1bWzFdXSRzZSwKICBsblJSID0gLltbNl1dW1sxXV0kYiwgbG5SUl9sb3dlciA9IC5bWzZdXVtbMV1dJGNpLmxiLCBsblJSX3VwcGVyID0gLltbNl1dW1sxXV0kY2kudWIsIGxuUlJfc2UgPSAuW1s2XV1bWzFdXSRzZQopKVssIGMoMSwgNzoxOCldCgpIZWFydCA8LSBhcy5kYXRhLmZyYW1lKG92ZXJhbGwxICU+JSBmaWx0ZXIoLiwgR3JvdXBpbmdUZXJtID09ICJIZWFydCIpICU+JSBtdXRhdGUoCiAgbG5DVlIgPSAuW1s0XV1bWzFdXSRiLCBsbkNWUl9sb3dlciA9IC5bWzRdXVtbMV1dJGNpLmxiLCBsbkNWUl91cHBlciA9IC5bWzRdXVtbMV1dJGNpLnViLCBsbkNWUl9zZSA9IC5bWzRdXVtbMV1dJHNlLAogIGxuVlIgPSAuW1s1XV1bWzFdXSRiLCBsblZSX2xvd2VyID0gLltbNV1dW1sxXV0kY2kubGIsIGxuVlJfdXBwZXIgPSAuW1s1XV1bWzFdXSRjaS51YiwgbG5WUl9zZSA9IC5bWzVdXVtbMV1dJHNlLAogIGxuUlIgPSAuW1s2XV1bWzFdXSRiLCBsblJSX2xvd2VyID0gLltbNl1dW1sxXV0kY2kubGIsIGxuUlJfdXBwZXIgPSAuW1s2XV1bWzFdXSRjaS51YiwgbG5SUl9zZSA9IC5bWzZdXVtbMV1dJHNlCikpWywgYygxLCA3OjE4KV0KCkV5ZSA8LSBhcy5kYXRhLmZyYW1lKG92ZXJhbGwxICU+JSBmaWx0ZXIoLiwgR3JvdXBpbmdUZXJtID09ICJFeWUiKSAlPiUgbXV0YXRlKAogIGxuQ1ZSID0gLltbNF1dW1sxXV0kYiwgbG5DVlJfbG93ZXIgPSAuW1s0XV1bWzFdXSRjaS5sYiwgbG5DVlJfdXBwZXIgPSAuW1s0XV1bWzFdXSRjaS51YiwgbG5DVlJfc2UgPSAuW1s0XV1bWzFdXSRzZSwKICBsblZSID0gLltbNV1dW1sxXV0kYiwgbG5WUl9sb3dlciA9IC5bWzVdXVtbMV1dJGNpLmxiLCBsblZSX3VwcGVyID0gLltbNV1dW1sxXV0kY2kudWIsIGxuVlJfc2UgPSAuW1s1XV1bWzFdXSRzZSwKICBsblJSID0gLltbNl1dW1sxXV0kYiwgbG5SUl9sb3dlciA9IC5bWzZdXVtbMV1dJGNpLmxiLCBsblJSX3VwcGVyID0gLltbNl1dW1sxXV0kY2kudWIsIGxuUlJfc2UgPSAuW1s2XV1bWzFdXSRzZQopKVssIGMoMSwgNzoxOCldCgpBbGwgPC0gYXMuZGF0YS5mcmFtZShvdmVyYWxsX2FsbDEgJT4lIG11dGF0ZSgKICBsbkNWUiA9IC5bWzJdXVtbMV1dJGIsIGxuQ1ZSX2xvd2VyID0gLltbMl1dW1sxXV0kY2kubGIsIGxuQ1ZSX3VwcGVyID0gLltbMl1dW1sxXV0kY2kudWIsIGxuQ1ZSX3NlID0gLltbMl1dW1sxXV0kc2UsIGxuVlIgPSAuW1szXV1bWzFdXSRiLCBsblZSX2xvd2VyID0gLltbM11dW1sxXV0kY2kubGIsIGxuVlJfdXBwZXIgPSAuW1szXV1bWzFdXSRjaS51YiwgbG5WUl9zZSA9IC5bWzNdXVtbMV1dJHNlLAogIGxuUlIgPSAuW1s0XV1bWzFdXSRiLCBsblJSX2xvd2VyID0gLltbNF1dW1sxXV0kY2kubGIsIGxuUlJfdXBwZXIgPSAuW1s0XV1bWzFdXSRjaS51YiwgbG5SUl9zZSA9IC5bWzRdXVtbMV1dJHNlCikpWywgYyg1OjE2KV0KCkFsbCRsbkNWUiA8LSBhcy5udW1lcmljKEFsbCRsbkNWUikKQWxsJGxuVlIgPC0gYXMubnVtZXJpYyhBbGwkbG5WUikKQWxsJGxuUlIgPC0gYXMubnVtZXJpYyhBbGwkbG5SUikKQWxsIDwtIEFsbCAlPiUgbXV0YXRlKEdyb3VwaW5nVGVybSA9ICJBbGwiKQoKb3ZlcmFsbDIgPC0gYmluZF9yb3dzKEJlaGF2aW91ciwgTW9ycGhvbG9neSwgTWV0YWJvbGlzbSwgUGh5c2lvbG9neSwgSW1tdW5vbG9neSwgSGVtYXRvbG9neSwgSGVhcnQsIEhlYXJpbmcsIEV5ZSwgQWxsKSAjRlo6IHdhcm5pbmdzIGFyZSBvawpgYGAKCiMjIFZpc3VhbGlzYXRpb24KCiMjIyMgUHJlcGFyYXRpb24gZm9yIHBsb3RzOiBDb3VudCBkYXRhLCBiYXNlZCBvbiBGaXJzdC1vcmRlciBtZXRhIGFuYWx5c2lzIHJlc3VsdHMKClJlLW9yZGVyIGdyb3VwaW5nIHRlcm1zIAoKYGBge3J9CgptZXRhX2NsZWFuJEdyb3VwaW5nVGVybSA8LSBmYWN0b3IobWV0YV9jbGVhbiRHcm91cGluZ1Rlcm0sIGxldmVscyA9IGMoIkJlaGF2aW91ciIsICJNb3JwaG9sb2d5IiwgIk1ldGFib2xpc20iLCAiUGh5c2lvbG9neSIsICJJbW11bm9sb2d5IiwgIkhlbWF0b2xvZ3kiLCAiSGVhcnQiLCAiSGVhcmluZyIsICJFeWUiKSkKbWV0YV9jbGVhbiRHcm91cGluZ1Rlcm0gPC0gZmFjdG9yKG1ldGFfY2xlYW4kR3JvdXBpbmdUZXJtLCByZXYobGV2ZWxzKG1ldGFfY2xlYW4kR3JvdXBpbmdUZXJtKSkpCgojICpQcmVwYXJlIGRhdGEgZm9yIGFsbCB0cmFpdHMKCm1ldGEucGxvdDIuYWxsIDwtIG1ldGFfY2xlYW4gJT4lCiAgc2VsZWN0KGxuQ1ZSLCBsblZSLCBsblJSLCBHcm91cGluZ1Rlcm0pICU+JQogIGFycmFuZ2UoR3JvdXBpbmdUZXJtKQoKbWV0YS5wbG90Mi5hbGwuYiA8LSBnYXRoZXIobWV0YS5wbG90Mi5hbGwsIHRyYWl0LCB2YWx1ZSwgYyhsbkNWUiwgbG5SUikpICMgbG5WUiwKCm1ldGEucGxvdDIuYWxsLmIkdHJhaXQgPC0gZmFjdG9yKG1ldGEucGxvdDIuYWxsLmIkdHJhaXQsIGxldmVscyA9IGMoImxuQ1ZSIiwgImxuUlIiKSkgIyAibG5WUiIsCgptZXRhLnBsb3QyLmFsbC5jIDwtIG1ldGEucGxvdDIuYWxsLmIgJT4lCiAgZ3JvdXBfYnlfYXQodmFycyh0cmFpdCwgR3JvdXBpbmdUZXJtKSkgJT4lCiAgc3VtbWFyaXNlKAogICAgbWFsZWJpYXMgPSBzdW0odmFsdWUgPiAwKSwgZmVtYWxlYmlhcyA9IHN1bSh2YWx1ZSA8PSAwKSwgdG90YWwgPSBtYWxlYmlhcyArIGZlbWFsZWJpYXMsCiAgICBtYWxlcGVyY2VudCA9IG1hbGViaWFzICogMTAwIC8gdG90YWwsIGZlbWFsZXBlcmNlbnQgPSBmZW1hbGViaWFzICogMTAwIC8gdG90YWwKICApCgptZXRhLnBsb3QyLmFsbC5jJGxhYmVsIDwtICJBbGwgdHJhaXRzIgoKIyByZXN0cnVjdHVyZSB0byBjcmVhdGUgc3RhY2tlZCBiYXIgcGxvdHMKCm1ldGEucGxvdDIuYWxsLmQgPC0gYXMuZGF0YS5mcmFtZShtZXRhLnBsb3QyLmFsbC5jKQptZXRhLnBsb3QyLmFsbC5lIDwtIGdhdGhlcihtZXRhLnBsb3QyLmFsbC5kLCBrZXkgPSBzZXgsIHZhbHVlID0gcGVyY2VudCwgbWFsZXBlcmNlbnQ6ZmVtYWxlcGVyY2VudCwgZmFjdG9yX2tleSA9IFRSVUUpCgojIGNyZWF0ZSBuZXcgc2FtcGxlIHNpemUgdmFyaWFibGUKCm1ldGEucGxvdDIuYWxsLmUkc2FtcGxlc2l6ZSA8LSB3aXRoKG1ldGEucGxvdDIuYWxsLmUsIGlmZWxzZShzZXggPT0gIm1hbGVwZXJjZW50IiwgbWFsZWJpYXMsIGZlbWFsZWJpYXMpKQoKIyBhZGQgc3VtbWFyeSByb3cgKCdBbGwnKSBhbmQgcmUtYXJyYW5nZSByb3dzIGludG8gY29ycmVjdCBvcmRlciBmb3IgcGxvdHRpbmcgI0ZaIGFkZGVkCgptZXRhLnBsb3QyLmFsbC5mIDwtIG1ldGEucGxvdDIuYWxsLmUgJT4lIGdyb3VwX2J5KHRyYWl0LCBzZXgpICU+JSAKCXN1bW1hcmlzZShHcm91cGluZ1Rlcm0gPSAiQWxsIiwgbWFsZWJpYXMgPSBzdW0obWFsZWJpYXMpLCBmZW1hbGViaWFzID0gc3VtKGZlbWFsZWJpYXMpLCB0b3RhbCA9IG1hbGViaWFzICsgZmVtYWxlYmlhcywgCglsYWJlbCA9ICJBbGwgdHJhaXRzIiwgc2FtcGxlc2l6ZSA9IHN1bShzYW1wbGVzaXplKSkgJT4lCgltdXRhdGUocGVyY2VudCA9IGlmZWxzZShzZXggPT0gImZlbWFsZXBlcmNlbnQiLCBmZW1hbGViaWFzKjEwMC8obWFsZWJpYXMrZmVtYWxlYmlhcyksIG1hbGViaWFzKjEwMC8obWFsZWJpYXMrZmVtYWxlYmlhcykpKSAlPiUKCWJpbmRfcm93cyhtZXRhLnBsb3QyLmFsbC5lLCAuKSAlPiUKCW11dGF0ZShyb3dudW1iZXIgPSByb3dfbnVtYmVyKCkpICU+JQoJLltjKDM3LCAxOjksIDM5LCAxMDoxOCwgMzgsIDE5OjI3LCA0MCwgMjg6MzYpLCBdCgptZXRhLnBsb3QyLmFsbC5mJEdyb3VwaW5nVGVybSA8LSBmYWN0b3IobWV0YS5wbG90Mi5hbGwuZiRHcm91cGluZ1Rlcm0sIGxldmVscyA9IGMoIkJlaGF2aW91ciIsICJNb3JwaG9sb2d5IiwgIk1ldGFib2xpc20iLCAiUGh5c2lvbG9neSIsICJJbW11bm9sb2d5IiwgIkhlbWF0b2xvZ3kiLCAiSGVhcnQiLCAiSGVhcmluZyIsICJFeWUiLCAiQWxsIikpIAptZXRhLnBsb3QyLmFsbC5mJEdyb3VwaW5nVGVybSA8LSBmYWN0b3IobWV0YS5wbG90Mi5hbGwuZiRHcm91cGluZ1Rlcm0sIHJldihsZXZlbHMobWV0YS5wbG90Mi5hbGwuZiRHcm91cGluZ1Rlcm0pKSkKCm1hbGViaWFzX0ZpZzJfYWxsdHJhaXRzIDwtCiAgZ2dwbG90KG1ldGEucGxvdDIuYWxsLmYpICsKICBhZXMoeCA9IEdyb3VwaW5nVGVybSwgeSA9IHBlcmNlbnQsIGZpbGwgPSBzZXgpICsKICBnZW9tX2NvbCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1MCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JheTQwIikgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSBzdWJzZXQobWV0YS5wbG90Mi5hbGwuZiwgc2FtcGxlc2l6ZSAhPSAwKSwgYWVzKGxhYmVsID0gc2FtcGxlc2l6ZSksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAuNSksCiAgICBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzLjUKICApICsKICBmYWNldF9ncmlkKAogICAgY29scyA9IHZhcnModHJhaXQpLCByb3dzID0gdmFycyhsYWJlbCksIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSAxOCksCiAgICBzY2FsZXMgPSAiZnJlZSIsIHNwYWNlID0gImZyZWUiCiAgKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNzAsIHNpemUgPSAxMCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxNSwgciA9IDE1LCBiID0gMTUsIGwgPSAxNSkpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9IE5VTEwsIGxpbmV0eXBlID0gImJsYW5rIiwgZmlsbCA9ICJncmF5OTAiKSwKICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG91ciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG9yID0gImdyYXk5NSIpLAogICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpCiAgKSArCiAgY29vcmRfZmxpcCgpCgojIG1hbGViaWFzX0ZpZzJfYWxsdHJhaXRzICAgICAjKHBhbmVsIEEgaW4gRmlndXJlIDQgaW4gbXMpCmBgYAoKIyMjIyBQcmVwYXJlIGRhdGEgZm9yIHRyYWl0cyB3aXRoIENJIG5vdCBvdmVybGFwcGluZyAwCmNyZWF0ZSBjb2x1bW4gd2l0aCAxPSBkaWZmZXJlbnQgZnJvbSB6ZXJvLCAwPSB6ZXJvIGluY2x1ZGVkIGluIENJCgpgYGB7cn0KCm1ldGEucGxvdDIuc2lnIDwtIG1ldGFfY2xlYW4gJT4lCiAgbXV0YXRlKAogICAgbG5DVlJzaWcgPSBpZmVsc2UobG5DVlJfbG93ZXIgKiBsbkNWUl91cHBlciA+IDAsIDEsIDApLCBsblZSc2lnID0gaWZlbHNlKGxuVlJfbG93ZXIgKiBsblZSX3VwcGVyID4gMCwgMSwgMCksCiAgICBsblJSc2lnID0gaWZlbHNlKGxuUlJfbG93ZXIgKiBsblJSX3VwcGVyID4gMCwgMSwgMCkKICApCgptZXRhLnBsb3QyLnNpZy5iIDwtIG1ldGEucGxvdDIuc2lnWywgYygibG5DVlIiLCAibG5SUiIsICJsbkNWUnNpZyIsICJsblZSc2lnIiwgImxuUlJzaWciLCAiR3JvdXBpbmdUZXJtIildICMgImxuVlIiLAoKbWV0YS5wbG90Mi5zaWcuYyA8LSBnYXRoZXIobWV0YS5wbG90Mi5zaWcuYiwgdHJhaXQsIHZhbHVlLCBsbkNWUjpsblJSKQptZXRhLnBsb3QyLnNpZy5jJHNpZyA8LSAicGxhY2Vob2xkZXIiCgptZXRhLnBsb3QyLnNpZy5jJHRyYWl0IDwtIGZhY3RvcihtZXRhLnBsb3QyLnNpZy5jJHRyYWl0LCBsZXZlbHMgPSBjKCJsbkNWUiIsICJsblJSIikpICMgImxuVlIiLAoKbWV0YS5wbG90Mi5zaWcuYyRzaWcgPC0gaWZlbHNlKG1ldGEucGxvdDIuc2lnLmMkdHJhaXQgPT0gImxuQ1ZSIiwgbWV0YS5wbG90Mi5zaWcuYyRsbkNWUnNpZywKICBpZmVsc2UobWV0YS5wbG90Mi5zaWcuYyR0cmFpdCA9PSAibG5WUiIsIG1ldGEucGxvdDIuc2lnLmMkbG5WUnNpZywgbWV0YS5wbG90Mi5zaWcuYyRsblJSc2lnKQopCgojIGNob29zaW5nIHNleCBiaWFzZWQgbG4tcmF0aW9zIHNpZ25pZmljYW50bHkgbGFyZ2VyIHRoYW4gMAptZXRhLnBsb3QyLnNpZy5tYWxlYmlhcyA8LSBtZXRhLnBsb3QyLnNpZy5jICU+JQogIGdyb3VwX2J5X2F0KHZhcnModHJhaXQsIEdyb3VwaW5nVGVybSkpICU+JQogIGZpbHRlcihzaWcgPT0gMSkgJT4lCiAgc3VtbWFyaXNlKG1hbGVfc2lnID0gc3VtKHZhbHVlID4gMCksIGZlbWFsZV9zaWcgPSBzdW0odmFsdWUgPCAwKSwgdG90YWwgPSBtYWxlX3NpZyArIGZlbWFsZV9zaWcpCgptZXRhLnBsb3QyLnNpZy5tYWxlYmlhcyA8LSB1bmdyb3VwKG1ldGEucGxvdDIuc2lnLm1hbGViaWFzKSAlPiUKICBhZGRfcm93KHRyYWl0ID0gImxuQ1ZSIiwgR3JvdXBpbmdUZXJtID0gIkhlYXJpbmciLCBtYWxlX3NpZyA9IDAsIGZlbWFsZV9zaWcgPSAwLCAuYmVmb3JlID0gNCkgJT4lICMgYWRkICJIZWFyaW5nIiBmb3IgbG5DVlIgKG5vdCBmaWx0ZXJlZCBhcyBvbmx5IHplcm9zKQogIG11dGF0ZShtYWxlcGVyY2VudCA9IG1hbGVfc2lnICogMTAwIC8gdG90YWwsIGZlbWFsZXBlcmNlbnQgPSBmZW1hbGVfc2lnICogMTAwIC8gdG90YWwpCgptZXRhLnBsb3QyLnNpZy5tYWxlYmlhcyRsYWJlbCA8LSAiQ0kgbm90IG92ZXJsYXBwaW5nIHplcm8iCgojIHJlc3RydWN0dXJlIHRvIGNyZWF0ZSBzdGFja2VkIGJhciBwbG90cwoKbWV0YS5wbG90Mi5zaWcuYm90aHNleGVzIDwtIGFzLmRhdGEuZnJhbWUobWV0YS5wbG90Mi5zaWcubWFsZWJpYXMpCm1ldGEucGxvdDIuc2lnLmJvdGhzZXhlcy5iIDwtIGdhdGhlcihtZXRhLnBsb3QyLnNpZy5ib3Roc2V4ZXMsIGtleSA9IHNleCwgdmFsdWUgPSBwZXJjZW50LCBtYWxlcGVyY2VudDpmZW1hbGVwZXJjZW50LCBmYWN0b3Jfa2V5ID0gVFJVRSkKCiMgY3JlYXRlIG5ldyBzYW1wbGUgc2l6ZSB2YXJpYWJsZQoKbWV0YS5wbG90Mi5zaWcuYm90aHNleGVzLmIkc2FtcGxlc2l6ZSA8LSB3aXRoKG1ldGEucGxvdDIuc2lnLmJvdGhzZXhlcy5iLCBpZmVsc2Uoc2V4ID09ICJtYWxlcGVyY2VudCIsIG1hbGVfc2lnLCBmZW1hbGVfc2lnKSkKCiMgKlBsb3QgRmlnMiBhbGwgc2lnbmlmaWNhbnQgcmVzdWx0cyAoQ0kgbm90IG92ZXJsYXBwaW5nIHplcm8pOgojICAgICBubyBzaWcuIGxuQ1ZSIGZvciAnSGVhcmluZycgaW4gZWl0aGVyIHNleDsgbm8gc2lnLiBtYWxlLWJpYXNlZCBsbkNWUiBmb3IgJ0ltbXVub2xvZ3knIGFuZCAnRXllLCBhbmQgbm8gc2lnLiBtYWxlLWJpYXNlZCBsblZSIGZvciAnRXllJwoKCm1hbGViaWFzX0ZpZzJfc2lndHJhaXRzIDwtCiAgZ2dwbG90KG1ldGEucGxvdDIuc2lnLmJvdGhzZXhlcy5iKSArCiAgYWVzKHggPSBHcm91cGluZ1Rlcm0sIHkgPSBwZXJjZW50LCBmaWxsID0gc2V4KSArCiAgZ2VvbV9jb2woKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNTAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImdyYXk0MCIpICsKICBnZW9tX3RleHQoCiAgICBkYXRhID0gc3Vic2V0KG1ldGEucGxvdDIuc2lnLmJvdGhzZXhlcy5iLCBzYW1wbGVzaXplICE9IDApLCBhZXMobGFiZWwgPSBzYW1wbGVzaXplKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IC41KSwKICAgIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDMuNQogICkgKwogIGZhY2V0X2dyaWQoCiAgICBjb2xzID0gdmFycyh0cmFpdCksIHJvd3MgPSB2YXJzKGxhYmVsKSwgbGFiZWxsZXIgPSBsYWJlbF93cmFwX2dlbih3aWR0aCA9IDE4KSwKICAgIHNjYWxlcyA9ICJmcmVlIiwgc3BhY2UgPSAiZnJlZSIKICApICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsKICB0aGVtZSgKICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDI3MCwgc2l6ZSA9IDEwLCBtYXJnaW4gPSBtYXJnaW4odCA9IDE1LCByID0gMTUsIGIgPSAxNSwgbCA9IDE1KSksCiAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gTlVMTCwgbGluZXR5cGUgPSAiYmxhbmsiLCBmaWxsID0gImdyYXk5MCIpLAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC41LCAibGluZXMiKSwKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9saW5lKGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3VyID0gImdyYXk5NSIpLAogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3IgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkKICApICsKICBjb29yZF9mbGlwKCkKYGBgCgpQcmVwYXJlIGRhdGEgZm9yIHRyYWl0cyB3aXRoIGVmZmVjdCBzaXplIHJhdGlvcyA+IDEwJSBsYXJnZXIgaW4gbWFsZXMKCmBgYHtyfQptZXRhLnBsb3QyLm92ZXIxMCA8LSBtZXRhX2NsZWFuICU+JQogIHNlbGVjdChsbkNWUiwgbG5SUiwgR3JvdXBpbmdUZXJtKSAlPiUKICBhcnJhbmdlKEdyb3VwaW5nVGVybSkgIyBsblZSLAoKbWV0YS5wbG90Mi5vdmVyMTAuYiA8LSBnYXRoZXIobWV0YS5wbG90Mi5vdmVyMTAsIHRyYWl0LCB2YWx1ZSwgYyhsbkNWUiwgbG5SUikpICMgbG5WUiwKCm1ldGEucGxvdDIub3ZlcjEwLmIkdHJhaXQgPC0gZmFjdG9yKG1ldGEucGxvdDIub3ZlcjEwLmIkdHJhaXQsIGxldmVscyA9IGMoImxuQ1ZSIiwgImxuUlIiKSkgIyAibG5WUiIsCgptZXRhLnBsb3QyLm92ZXIxMC5jIDwtIG1ldGEucGxvdDIub3ZlcjEwLmIgJT4lCiAgZ3JvdXBfYnlfYXQodmFycyh0cmFpdCwgR3JvdXBpbmdUZXJtKSkgJT4lCiAgc3VtbWFyaXNlKAogICAgbWFsZWJpYXMgPSBzdW0odmFsdWUgPiBsb2coMTEgLyAxMCkpLCBmZW1hbGViaWFzID0gc3VtKHZhbHVlIDwgbG9nKDkgLyAxMCkpLCB0b3RhbCA9IG1hbGViaWFzICsgZmVtYWxlYmlhcywKICAgIG1hbGVwZXJjZW50ID0gbWFsZWJpYXMgKiAxMDAgLyB0b3RhbCwgZmVtYWxlcGVyY2VudCA9IGZlbWFsZWJpYXMgKiAxMDAgLyB0b3RhbAogICkKCm1ldGEucGxvdDIub3ZlcjEwLmMkbGFiZWwgPC0gIlNleCBkaWZmZXJlbmNlIGluIG0vZiByYXRpb3MgPiAxMCUiCgojIHJlc3RydWN0dXJlIHRvIGNyZWF0ZSBzdGFja2VkIGJhciBwbG90cwoKbWV0YS5wbG90Mi5vdmVyMTAuYyA8LSBhcy5kYXRhLmZyYW1lKG1ldGEucGxvdDIub3ZlcjEwLmMpCm1ldGEucGxvdDIub3ZlcjEwLmQgPC0gZ2F0aGVyKG1ldGEucGxvdDIub3ZlcjEwLmMsIGtleSA9IHNleCwgdmFsdWUgPSBwZXJjZW50LCBtYWxlcGVyY2VudDpmZW1hbGVwZXJjZW50LCBmYWN0b3Jfa2V5ID0gVFJVRSkKCiMgY3JlYXRlIG5ldyBzYW1wbGUgc2l6ZSB2YXJpYWJsZQoKbWV0YS5wbG90Mi5vdmVyMTAuZCRzYW1wbGVzaXplIDwtIHdpdGgobWV0YS5wbG90Mi5vdmVyMTAuZCwgaWZlbHNlKHNleCA9PSAibWFsZXBlcmNlbnQiLCBtYWxlYmlhcywgZmVtYWxlYmlhcykpCgojICpQbG90IEZpZzIgU2V4IGRpZmZlcmVuY2UgaW4gbS9mIHJhdGlvID4gMTAlCm1hbGViaWFzX0ZpZzJfb3ZlcjEwIDwtCiAgZ2dwbG90KG1ldGEucGxvdDIub3ZlcjEwLmQpICsKICBhZXMoeCA9IEdyb3VwaW5nVGVybSwgeSA9IHBlcmNlbnQsIGZpbGwgPSBzZXgpICsKICBnZW9tX2NvbCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1MCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JheTQwIikgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSBzdWJzZXQobWV0YS5wbG90Mi5vdmVyMTAuZCwgc2FtcGxlc2l6ZSAhPSAwKSwgYWVzKGxhYmVsID0gc2FtcGxlc2l6ZSksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAuNSksCiAgICBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzLjUKICApICsKICBmYWNldF9ncmlkKAogICAgY29scyA9IHZhcnModHJhaXQpLCByb3dzID0gdmFycyhsYWJlbCksIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSAxOCksCiAgICBzY2FsZXMgPSAiZnJlZSIsIHNwYWNlID0gImZyZWUiCiAgKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNzAsIHNpemUgPSAxMCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxNSwgciA9IDE1LCBiID0gMTUsIGwgPSAxNSkpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOVUxMLCBsaW5ldHlwZSA9ICJibGFuayIsIGZpbGwgPSAiZ3JheTkwIiksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICkgKwogIGNvb3JkX2ZsaXAoKQoKIyBtYWxlYmlhc19GaWcyX292ZXIxMCAgKFBhbmVsIEMgaW4gRmlnIDUgaW4gbXMpCmBgYAoKCiMjIyAgT3ZlcmFsbCByZXN1bHRzIG9mIHNlY29uZCBvcmRlciBtZXRhIGFuYWx5c2lzIChGaWd1cmUgNDogb3ZlcmFsbCwgRmlndXJlIDU6IHNleC1iaWFzKQojIyMjIFJlc3RydWN0dXJlIGRhdGEgZm9yIHBsb3R0aW5nIApEYXRhIGFyZSByZXN0cnVjdHVyZWQsIGFuZCBncm91cGluZyB0ZXJtcyBhcmUgYmVpbmcgcmUtb3JkZXJlZAoKYGBge3J9Cm92ZXJhbGwzIDwtIGdhdGhlcihvdmVyYWxsMiwgcGFyYW1ldGVyLCB2YWx1ZSwgYyhsbkNWUiwgbG5SUiksIGZhY3Rvcl9rZXkgPSBUUlVFKSAjIGxuVlIsCgpsbkNWUi5jaSA8LSBvdmVyYWxsMyAlPiUKICBmaWx0ZXIocGFyYW1ldGVyID09ICJsbkNWUiIpICU+JQogIG11dGF0ZShjaS5sb3cgPSBsbkNWUl9sb3dlciwgY2kuaGlnaCA9IGxuQ1ZSX3VwcGVyKQpsblZSLmNpIDwtIG92ZXJhbGwzICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImxuVlIiKSAlPiUKICBtdXRhdGUoY2kubG93ID0gbG5WUl9sb3dlciwgY2kuaGlnaCA9IGxuVlJfdXBwZXIpCmxuUlIuY2kgPC0gb3ZlcmFsbDMgJT4lCiAgZmlsdGVyKHBhcmFtZXRlciA9PSAibG5SUiIpICU+JQogIG11dGF0ZShjaS5sb3cgPSBsblJSX2xvd2VyLCBjaS5oaWdoID0gbG5SUl91cHBlcikKCm92ZXJhbGw0IDwtIGJpbmRfcm93cyhsbkNWUi5jaSwgbG5SUi5jaSkgJT4lIHNlbGVjdChHcm91cGluZ1Rlcm0sIHBhcmFtZXRlciwgdmFsdWUsIGNpLmxvdywgY2kuaGlnaCkgIyBsblZSLmNpLAoKIyByZS1vcmRlciBHcm91cGluZyBUZXJtcwoKb3ZlcmFsbDQkR3JvdXBpbmdUZXJtIDwtIGZhY3RvcihvdmVyYWxsNCRHcm91cGluZ1Rlcm0sIGxldmVscyA9IGMoIkJlaGF2aW91ciIsICJNb3JwaG9sb2d5IiwgIk1ldGFib2xpc20iLCAiUGh5c2lvbG9neSIsICJJbW11bm9sb2d5IiwgIkhlbWF0b2xvZ3kiLCAiSGVhcnQiLCAiSGVhcmluZyIsICJFeWUiLCAiQWxsIikpCm92ZXJhbGw0JEdyb3VwaW5nVGVybSA8LSBmYWN0b3Iob3ZlcmFsbDQkR3JvdXBpbmdUZXJtLCByZXYobGV2ZWxzKG92ZXJhbGw0JEdyb3VwaW5nVGVybSkpKQpvdmVyYWxsNCRsYWJlbCA8LSAiQWxsIHRyYWl0cyIKCmthYmxlKGNiaW5kKG92ZXJhbGw0LCBvdmVyYWxsNCkpICU+JQogIGthYmxlX3N0eWxpbmcoKSAlPiUKICBzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiLCBoZWlnaHQgPSAiMjAwcHgiKQpgYGAKCiMjIyMgUHJlcGFyYXRpb24gZm9yIFBsb3RzIEZJR1VSRSA0QiAmIDVCLCA1RCAoU2Vjb25kLW9yZGVyIG1ldGEgYW5hbHlzaXMgcmVzdWx0cykKUHJlcGFyYXRpb246IFN1Yi1QbG90ICBmb3IgRmlndXJlIDM6IGFsbCB0cmFpdHMgKDRCKQoKYGBge3J9CgpNZXRhbWV0YV9GaWczX2FsbHRyYWl0cyA8LSBvdmVyYWxsNCAlPiUKCiAgZ2dwbG90KGFlcyh5ID0gR3JvdXBpbmdUZXJtLCB4ID0gdmFsdWUpKSArCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKAogICAgeG1pbiA9IGNpLmxvdywKICAgIHhtYXggPSBjaS5oaWdoCiAgKSwKICBoZWlnaHQgPSAwLjEsIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHBhcmFtZXRlciksCiAgICBmaWxsID0gImJsYWNrIiwKICAgIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDIuMiwKICAgIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBsaW1pdHMgPSBjKC0wLjI0LCAwLjI1KSwKICAgIGJyZWFrcyA9IGMoLTAuMiwgLTAuMSwgMCwgMC4xLCAwLjIpLAogICAgbmFtZSA9ICJFZmZlY3Qgc2l6ZSIKICApICsKICBnZW9tX3ZsaW5lKAogICAgeGludGVyY2VwdCA9IDAsCiAgICBjb2xvciA9ICJibGFjayIsCiAgICBsaW5ldHlwZSA9ICJkYXNoZWQiCiAgKSArCiAgZmFjZXRfZ3JpZCgKICAgIGNvbHMgPSB2YXJzKHBhcmFtZXRlciksIHJvd3MgPSB2YXJzKGxhYmVsKSwKICAgIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSAyMyksCiAgICBzY2FsZXMgPSAiZnJlZSIsCiAgICBzcGFjZSA9ICJmcmVlIgogICkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjcwLCBzaXplID0gMTAsIG1hcmdpbiA9IG1hcmdpbih0ID0gMTUsIHIgPSAxNSwgYiA9IDE1LCBsID0gMTUpKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOVUxMLCBsaW5ldHlwZSA9ICJibGFuayIsIGZpbGwgPSAiZ3JheTkwIiksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0KSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgTWV0YW1ldGFfRmlnM19hbGx0cmFpdHMKYGBgCgojIyMjIEZpZ3VyZSA1IC0gdHJhaXRzIHdpdGggQ0kgbm90IG92ZXJsYXBwaW5nIDAgClByZXBhcmUgZGF0YSAKY3JlYXRlIGNvbHVtbiB3aXRoIDE9IGRpZmZlcmVudCBmcm9tIHplcm8sIDA9IHplcm8gaW5jbHVkZWQgaW4gQ0kKTWFsZS1iaWFzZWQgKHNpZ25pZmljYW50KSB0cmFpdHMKCmBgYHtyfQptZXRhLm1hbGUucGxvdDMuc2lnIDwtIG1ldGFjb21ibyAlPiUKICBtdXRhdGUoCiAgICBzaWdDVlIgPSBpZmVsc2UobG5DVlJfbG93ZXIgPiAwLCAxLCAwKSwKICAgIHNpZ1ZSID0gaWZlbHNlKGxuVlJfbG93ZXIgPiAwLCAxLCAwKSwKICAgIHNpZ1JSID0gaWZlbHNlKGxuUlJfbG93ZXIgPiAwLCAxLCAwKQogICkKCiMgU2lnbmlmaWNhbnQgc3Vic2V0IGZvciBsbkNWUgptZXRhY29tYm9fbWFsZS5wbG90My5DVlIgPC0gbWV0YS5tYWxlLnBsb3QzLnNpZyAlPiUKICBmaWx0ZXIoc2lnQ1ZSID09IDEpICU+JQogIGdyb3VwX2J5KEdyb3VwaW5nVGVybSkgJT4lCiAgbmVzdCgpCgptZXRhY29tYm9fbWFsZS5wbG90My5DVlIuYWxsIDwtIG1ldGEubWFsZS5wbG90My5zaWcgJT4lCiAgZmlsdGVyKHNpZ0NWUiA9PSAxKSAlPiUKICBuZXN0KCkKCiMgU2lnbmlmaWNhbnQgc3Vic2V0IGZvciBsblZSCm1ldGFjb21ib19tYWxlLnBsb3QzLlZSIDwtIG1ldGEubWFsZS5wbG90My5zaWcgJT4lCiAgZmlsdGVyKHNpZ1ZSID09IDEpICU+JQogIGdyb3VwX2J5KEdyb3VwaW5nVGVybSkgJT4lCiAgbmVzdCgpCgptZXRhY29tYm9fbWFsZS5wbG90My5WUi5hbGwgPC0gbWV0YS5tYWxlLnBsb3QzLnNpZyAlPiUKICBmaWx0ZXIoc2lnVlIgPT0gMSkgJT4lCiAgbmVzdCgpCgojIFNpZ25pZmljYW50IHN1YnNldCBmb3IgbG5SUgptZXRhY29tYm9fbWFsZS5wbG90My5SUiA8LSBtZXRhLm1hbGUucGxvdDMuc2lnICU+JQogIGZpbHRlcihzaWdSUiA9PSAxKSAlPiUKICBncm91cF9ieShHcm91cGluZ1Rlcm0pICU+JQogIG5lc3QoKQoKbWV0YWNvbWJvX21hbGUucGxvdDMuUlIuYWxsIDwtIG1ldGEubWFsZS5wbG90My5zaWcgJT4lCiAgZmlsdGVyKHNpZ1JSID09IDEpICU+JQogIG5lc3QoKQoKIyAqKkZpbmFsIGZpeGVkIGVmZmVjdHMgbWV0YS1hbmFseXNlcyB3aXRoaW4gZ3JvdXBpbmcgdGVybXMsIHdpdGggU0Ugb2YgdGhlIGVzdGltYXRlCgpwbG90My5tYWxlLm1ldGEuQ1ZSIDwtIG1ldGFjb21ib19tYWxlLnBsb3QzLkNWUiAlPiUKICBtdXRhdGUobW9kZWxfbG5DVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsbkNWUiwgc2VpID0gKC54JGxuQ1ZSX3VwcGVyIC0gLngkbG5DVlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgpwbG90My5tYWxlLm1ldGEuVlIgPC0gbWV0YWNvbWJvX21hbGUucGxvdDMuVlIgJT4lCiAgbXV0YXRlKG1vZGVsX2xuVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsblZSLCBzZWkgPSAoLngkbG5WUl91cHBlciAtIC54JGxuVlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgpwbG90My5tYWxlLm1ldGEuUlIgPC0gbWV0YWNvbWJvX21hbGUucGxvdDMuUlIgJT4lCiAgbXV0YXRlKG1vZGVsX2xuUlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsblJSLCBzZWkgPSAoLngkbG5SUl91cHBlciAtIC54JGxuUlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgojIEFjcm9zcyBhbGwgZ3JvdXBpbmcgdGVybXMgIwoKcGxvdDMubWFsZS5tZXRhLkNWUi5hbGwgPC0gbWV0YWNvbWJvX21hbGUucGxvdDMuQ1ZSLmFsbCAlPiUKICBtdXRhdGUobW9kZWxfbG5DVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsbkNWUiwgc2VpID0gKC54JGxuQ1ZSX3VwcGVyIC0gLngkbG5DVlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgpwbG90My5tYWxlLm1ldGEuQ1ZSLmFsbCA8LSBwbG90My5tYWxlLm1ldGEuQ1ZSLmFsbCAlPiUgbXV0YXRlKEdyb3VwaW5nVGVybSA9ICJBbGwiKQoKcGxvdDMubWFsZS5tZXRhLlZSLmFsbCA8LSBtZXRhY29tYm9fbWFsZS5wbG90My5WUi5hbGwgJT4lCiAgbXV0YXRlKG1vZGVsX2xuVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsblZSLCBzZWkgPSAoLngkbG5WUl91cHBlciAtIC54JGxuVlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgpwbG90My5tYWxlLm1ldGEuVlIuYWxsIDwtIHBsb3QzLm1hbGUubWV0YS5WUi5hbGwgJT4lIG11dGF0ZShHcm91cGluZ1Rlcm0gPSAiQWxsIikKCnBsb3QzLm1hbGUubWV0YS5SUi5hbGwgPC0gbWV0YWNvbWJvX21hbGUucGxvdDMuUlIuYWxsICU+JQogIG11dGF0ZShtb2RlbF9sblJSID0gbWFwKGRhdGEsIH4gbWV0YWZvcjo6cm1hLnVuaSgKICAgIHlpID0gLngkbG5SUiwgc2VpID0gKC54JGxuUlJfdXBwZXIgLSAueCRsblJSX2xvd2VyKSAvICgyICogMS45NiksCiAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDApLCB2ZXJib3NlID0gRgogICkpKQoKcGxvdDMubWFsZS5tZXRhLlJSLmFsbCA8LSBwbG90My5tYWxlLm1ldGEuUlIuYWxsICU+JSBtdXRhdGUoR3JvdXBpbmdUZXJtID0gIkFsbCIpCgojIENvbWJpbmUgd2l0aCBzZXBhcmF0ZSBncm91cGluZyB0ZXJtIHJlc3VsdHMKCnBsb3QzLm1hbGUubWV0YS5DVlIgPC0gYmluZF9yb3dzKHBsb3QzLm1hbGUubWV0YS5DVlIsIHBsb3QzLm1hbGUubWV0YS5DVlIuYWxsKQpwbG90My5tYWxlLm1ldGEuVlIgPC0gYmluZF9yb3dzKHBsb3QzLm1hbGUubWV0YS5WUiwgcGxvdDMubWFsZS5tZXRhLlZSLmFsbCkKcGxvdDMubWFsZS5tZXRhLlJSIDwtIGJpbmRfcm93cyhwbG90My5tYWxlLm1ldGEuUlIsIHBsb3QzLm1hbGUubWV0YS5SUi5hbGwpCgojICoqUmUtc3RydWN0dXJlIGRhdGEgZm9yIGVhY2ggZ3JvdXBpbmcgdGVybTsgZGVsZXRlIHVuLXVzZWQgdmFyaWFibGVzCgpwbG90My5tYWxlLm1ldGEuQ1ZSLmIgPC0gYXMuZGF0YS5mcmFtZShwbG90My5tYWxlLm1ldGEuQ1ZSICU+JSBncm91cF9ieShHcm91cGluZ1Rlcm0pICU+JQogIG11dGF0ZSgKICAgIGxuQ1ZSID0gbWFwX2RibChtb2RlbF9sbkNWUiwgcGx1Y2soMikpLCBsbkNWUl9sb3dlciA9IG1hcF9kYmwobW9kZWxfbG5DVlIsIHBsdWNrKDYpKSwKICAgIGxuQ1ZSX3VwcGVyID0gbWFwX2RibChtb2RlbF9sbkNWUiwgcGx1Y2soNykpLCBsbkNWUl9zZSA9IG1hcF9kYmwobW9kZWxfbG5DVlIsIHBsdWNrKDMpKQogICkpWywgYygxLCA0OjcpXQphZGQucm93LmhlYXJpbmcgPC0gYXMuZGF0YS5mcmFtZSh0KGMoIkhlYXJpbmciLCBOQSwgTkEsIE5BLCBOQSkpKSAlPiUgc2V0TmFtZXMobmFtZXMocGxvdDMubWFsZS5tZXRhLkNWUi5iKSkKCnBsb3QzLm1hbGUubWV0YS5DVlIuYiA8LSBiaW5kX3Jvd3MocGxvdDMubWFsZS5tZXRhLkNWUi5iLCBhZGQucm93LmhlYXJpbmcpCnBsb3QzLm1hbGUubWV0YS5DVlIuYiA8LSBwbG90My5tYWxlLm1ldGEuQ1ZSLmJbb3JkZXIocGxvdDMubWFsZS5tZXRhLkNWUi5iJEdyb3VwaW5nVGVybSksIF0KCnBsb3QzLm1hbGUubWV0YS5WUi5iIDwtIGFzLmRhdGEuZnJhbWUocGxvdDMubWFsZS5tZXRhLlZSICU+JSBncm91cF9ieShHcm91cGluZ1Rlcm0pICU+JQogIG11dGF0ZSgKICAgIGxuVlIgPSBtYXBfZGJsKG1vZGVsX2xuVlIsIHBsdWNrKDIpKSwgbG5WUl9sb3dlciA9IG1hcF9kYmwobW9kZWxfbG5WUiwgcGx1Y2soNikpLAogICAgbG5WUl91cHBlciA9IG1hcF9kYmwobW9kZWxfbG5WUiwgcGx1Y2soNykpLCBsblZSX3NlID0gbWFwX2RibChtb2RlbF9sblZSLCBwbHVjaygzKSkKICApKVssIGMoMSwgNDo3KV0KcGxvdDMubWFsZS5tZXRhLlZSLmIgPC0gcGxvdDMubWFsZS5tZXRhLlZSLmJbb3JkZXIocGxvdDMubWFsZS5tZXRhLlZSLmIkR3JvdXBpbmdUZXJtKSwgXQoKcGxvdDMubWFsZS5tZXRhLlJSLmIgPC0gYXMuZGF0YS5mcmFtZShwbG90My5tYWxlLm1ldGEuUlIgJT4lIGdyb3VwX2J5KEdyb3VwaW5nVGVybSkgJT4lCiAgbXV0YXRlKAogICAgbG5SUiA9IG1hcF9kYmwobW9kZWxfbG5SUiwgcGx1Y2soMikpLCBsblJSX2xvd2VyID0gbWFwX2RibChtb2RlbF9sblJSLCBwbHVjayg2KSksCiAgICBsblJSX3VwcGVyID0gbWFwX2RibChtb2RlbF9sblJSLCBwbHVjayg3KSksIGxuUlJfc2UgPSBtYXBfZGJsKG1vZGVsX2xuUlIsIHBsdWNrKDMpKQogICkpWywgYygxLCA0OjcpXQpwbG90My5tYWxlLm1ldGEuUlIuYiA8LSBwbG90My5tYWxlLm1ldGEuUlIuYltvcmRlcihwbG90My5tYWxlLm1ldGEuUlIuYiRHcm91cGluZ1Rlcm0pLCBdCgpvdmVyYWxsLm1hbGUucGxvdDMgPC0gZnVsbF9qb2luKHBsb3QzLm1hbGUubWV0YS5DVlIuYiwgcGxvdDMubWFsZS5tZXRhLlZSLmIpCm92ZXJhbGwubWFsZS5wbG90MyA8LSBmdWxsX2pvaW4ob3ZlcmFsbC5tYWxlLnBsb3QzLCBwbG90My5tYWxlLm1ldGEuUlIuYikKCm92ZXJhbGwubWFsZS5wbG90MyRHcm91cGluZ1Rlcm0gPC0gZmFjdG9yKG92ZXJhbGwubWFsZS5wbG90MyRHcm91cGluZ1Rlcm0sIGxldmVscyA9IGMoIkJlaGF2aW91ciIsICJNb3JwaG9sb2d5IiwgIk1ldGFib2xpc20iLCAiUGh5c2lvbG9neSIsICJJbW11bm9sb2d5IiwgIkhlbWF0b2xvZ3kiLCAiSGVhcnQiLCAiSGVhcmluZyIsICJFeWUiLCAiQWxsIikpCm92ZXJhbGwubWFsZS5wbG90MyRHcm91cGluZ1Rlcm0gPC0gZmFjdG9yKG92ZXJhbGwubWFsZS5wbG90MyRHcm91cGluZ1Rlcm0sIHJldihsZXZlbHMob3ZlcmFsbC5tYWxlLnBsb3QzJEdyb3VwaW5nVGVybSkpKQoKIyBhZGQgbWlzc2luZyBHcm91cGluZ1Rlcm1zIGZvciBwbG90Cm92ZXJhbGwubWFsZS5wbG90MyA8LSBhZGRfcm93KG92ZXJhbGwubWFsZS5wbG90MywgR3JvdXBpbmdUZXJtID0gIkJlaGF2aW91ciIpCm92ZXJhbGwubWFsZS5wbG90MyA8LSBhZGRfcm93KG92ZXJhbGwubWFsZS5wbG90MywgR3JvdXBpbmdUZXJtID0gIkltbXVub2xvZ3kiKQpvdmVyYWxsLm1hbGUucGxvdDMgPC0gYWRkX3JvdyhvdmVyYWxsLm1hbGUucGxvdDMsIEdyb3VwaW5nVGVybSA9ICJFeWUiKQoKb3ZlcmFsbC5tYWxlLnBsb3QzJEdyb3VwaW5nVGVybSA8LSBmYWN0b3Iob3ZlcmFsbC5tYWxlLnBsb3QzJEdyb3VwaW5nVGVybSwgbGV2ZWxzID0gYygiQmVoYXZpb3VyIiwgIk1vcnBob2xvZ3kiLCAiTWV0YWJvbGlzbSIsICJQaHlzaW9sb2d5IiwgIkltbXVub2xvZ3kiLCAiSGVtYXRvbG9neSIsICJIZWFydCIsICJIZWFyaW5nIiwgIkV5ZSIsICJBbGwiKSkKb3ZlcmFsbC5tYWxlLnBsb3QzJEdyb3VwaW5nVGVybSA8LSBmYWN0b3Iob3ZlcmFsbC5tYWxlLnBsb3QzJEdyb3VwaW5nVGVybSwgcmV2KGxldmVscyhvdmVyYWxsLm1hbGUucGxvdDMkR3JvdXBpbmdUZXJtKSkpCgojIHN0cihvdmVyYWxsLm1hbGUucGxvdDMpCmBgYAoKClJlc3RydWN0dXJlIE1BTEUgZGF0YSBmb3IgcGxvdHRpbmcgCgpgYGB7cn0Kb3ZlcmFsbDMubWFsZS5zaWcgPC0gZ2F0aGVyKG92ZXJhbGwubWFsZS5wbG90MywgcGFyYW1ldGVyLCB2YWx1ZSwgYyhsbkNWUiwgbG5SUiksIGZhY3Rvcl9rZXkgPSBUUlVFKSAjIGxuVlIsCgpsbkNWUi5jaSA8LSBvdmVyYWxsMy5tYWxlLnNpZyAlPiUKICBmaWx0ZXIocGFyYW1ldGVyID09ICJsbkNWUiIpICU+JQogIG11dGF0ZShjaS5sb3cgPSBsbkNWUl9sb3dlciwgY2kuaGlnaCA9IGxuQ1ZSX3VwcGVyKQojIGxuVlIuY2kgPC0gb3ZlcmFsbDMubWFsZS5zaWcgICU+JSBmaWx0ZXIocGFyYW1ldGVyID09ICJsblZSIikgJT4lIG11dGF0ZShjaS5sb3cgPSBsblZSX2xvd2VyLCBjaS5oaWdoID0gbG5WUl91cHBlcikKbG5SUi5jaSA8LSBvdmVyYWxsMy5tYWxlLnNpZyAlPiUKICBmaWx0ZXIocGFyYW1ldGVyID09ICJsblJSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuUlJfbG93ZXIsIGNpLmhpZ2ggPSBsblJSX3VwcGVyKQoKb3ZlcmFsbDQubWFsZS5zaWcgPC0gYmluZF9yb3dzKGxuQ1ZSLmNpLCBsblJSLmNpKSAlPiUgc2VsZWN0KEdyb3VwaW5nVGVybSwgcGFyYW1ldGVyLCB2YWx1ZSwgY2kubG93LCBjaS5oaWdoKSAjIGxuVlIuY2ksCgpvdmVyYWxsNC5tYWxlLnNpZyRsYWJlbCA8LSAiQ0kgbm90IG92ZXJsYXBwaW5nIHplcm8iCmBgYAoKUGxvdCBGaWc1YiBhbGwgc2lnbmlmaWNhbnQgcmVzdWx0cyAoQ0kgbm90IG92ZXJsYXBwaW5nIHplcm8pIGZvciBtYWxlcwoKYGBge3J9CgpNZXRhbWV0YV9GaWczX21hbGUuc2lnIDwtIG92ZXJhbGw0Lm1hbGUuc2lnICU+JQogIGdncGxvdChhZXMoeSA9IEdyb3VwaW5nVGVybSwgeCA9IHZhbHVlKSkgKwogIGdlb21fZXJyb3JiYXJoKGFlcygKICAgIHhtaW4gPSBjaS5sb3csCiAgICB4bWF4ID0gY2kuaGlnaAogICksCiAgaGVpZ2h0ID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBwYXJhbWV0ZXIpLAogICAgZmlsbCA9ICJtZWRpdW1hcXVhbWFyaW5lIiwgY29sb3IgPSAibWVkaXVtYXF1YW1hcmluZSIsIHNpemUgPSAyLjIsCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbGltaXRzID0gYygwLCAwLjQpLAogICAgYnJlYWtzID0gYygwLCAwLjMpLAogICAgbmFtZSA9ICJFZmZlY3Qgc2l6ZSIKICApICsKICBnZW9tX3ZsaW5lKAogICAgeGludGVyY2VwdCA9IDAsCiAgICBjb2xvciA9ICJibGFjayIsCiAgICBsaW5ldHlwZSA9ICJkYXNoZWQiCiAgKSArCiAgZmFjZXRfZ3JpZCgKICAgIGNvbHMgPSB2YXJzKHBhcmFtZXRlciksIHJvd3MgPSB2YXJzKGxhYmVsKSwKICAgIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSAyMyksCiAgICBzY2FsZXMgPSAiZnJlZSIsCiAgICBzcGFjZSA9ICJmcmVlIgogICkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjcwLCBzaXplID0gMTAsIG1hcmdpbiA9IG1hcmdpbih0ID0gMTUsIHIgPSAxNSwgYiA9IDE1LCBsID0gMTUpKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOVUxMLCBsaW5ldHlwZSA9ICJibGFuayIsIGZpbGwgPSAiZ3JheTkwIiksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgTWV0YW1ldGFfRmlnM19tYWxlLnNpZwpgYGAKCiMjIyMgRmVtYWxlIEZpZ3VyZSwgc2lnbmlmaWNhbnQgdHJhaXRzCkZlbWFsZSBGaWc1QiBzaWcKClByZXBhcmUgZGF0YSBmb3IgdHJhaXRzIHdpdGggQ0kgbm90IG92ZXJsYXBwaW5nIDAKY3JlYXRlIGNvbHVtbiB3aXRoIDE9IGRpZmZlcmVudCBmcm9tIHplcm8sIDA9IHplcm8gaW5jbHVkZWQgaW4gQ0kKCmBgYHtyfQoKIyBmZW1hbGUtYmlhc2VkIHRyYWl0cwoKbWV0YS5mZW1hbGUucGxvdDMuc2lnIDwtIG1ldGFjb21ibyAlPiUKICBtdXRhdGUoCiAgICBzaWdDVlIgPSBpZmVsc2UobG5DVlJfdXBwZXIgPCAwLCAxLCAwKSwKICAgIHNpZ1ZSID0gaWZlbHNlKGxuVlJfdXBwZXIgPCAwLCAxLCAwKSwKICAgIHNpZ1JSID0gaWZlbHNlKGxuUlJfdXBwZXIgPCAwLCAxLCAwKQogICkKCiMgU2lnbmlmaWNhbnQgc3Vic2V0IGZvciBsbkNWUgoKbWV0YWNvbWJvX2ZlbWFsZS5wbG90My5DVlIgPC0gbWV0YS5mZW1hbGUucGxvdDMuc2lnICU+JQogIGZpbHRlcihzaWdDVlIgPT0gMSkgJT4lCiAgZ3JvdXBfYnkoR3JvdXBpbmdUZXJtKSAlPiUKICBuZXN0KCkKCm1ldGFjb21ib19mZW1hbGUucGxvdDMuQ1ZSLmFsbCA8LSBtZXRhLmZlbWFsZS5wbG90My5zaWcgJT4lCiAgZmlsdGVyKHNpZ0NWUiA9PSAxKSAlPiUKICBuZXN0KCkKCiMgU2lnbmlmaWNhbnQgc3Vic2V0IGZvciBsblZSCgptZXRhY29tYm9fZmVtYWxlLnBsb3QzLlZSIDwtIG1ldGEuZmVtYWxlLnBsb3QzLnNpZyAlPiUKICBmaWx0ZXIoc2lnVlIgPT0gMSkgJT4lCiAgZ3JvdXBfYnkoR3JvdXBpbmdUZXJtKSAlPiUKICBuZXN0KCkKCm1ldGFjb21ib19mZW1hbGUucGxvdDMuVlIuYWxsIDwtIG1ldGEuZmVtYWxlLnBsb3QzLnNpZyAlPiUKICBmaWx0ZXIoc2lnVlIgPT0gMSkgJT4lCiAgbmVzdCgpCgojIFNpZ25pZmljYW50IHN1YnNldCBmb3IgbG5SUgoKbWV0YWNvbWJvX2ZlbWFsZS5wbG90My5SUiA8LSBtZXRhLmZlbWFsZS5wbG90My5zaWcgJT4lCiAgZmlsdGVyKHNpZ1JSID09IDEpICU+JQogIGdyb3VwX2J5KEdyb3VwaW5nVGVybSkgJT4lCiAgbmVzdCgpCgptZXRhY29tYm9fZmVtYWxlLnBsb3QzLlJSLmFsbCA8LSBtZXRhLmZlbWFsZS5wbG90My5zaWcgJT4lCiAgZmlsdGVyKHNpZ1JSID09IDEpICU+JQogIG5lc3QoKQoKIyAqKkZpbmFsIGZpeGVkIGVmZmVjdHMgbWV0YS1hbmFseXNlcyB3aXRoaW4gZ3JvdXBpbmcgdGVybXMsIHdpdGggU0Ugb2YgdGhlIGVzdGltYXRlCgpwbG90My5mZW1hbGUubWV0YS5DVlIgPC0gbWV0YWNvbWJvX2ZlbWFsZS5wbG90My5DVlIgJT4lCiAgbXV0YXRlKG1vZGVsX2xuQ1ZSID0gbWFwKGRhdGEsIH4gbWV0YWZvcjo6cm1hLnVuaSgKICAgIHlpID0gLngkbG5DVlIsIHNlaSA9ICgueCRsbkNWUl91cHBlciAtIC54JGxuQ1ZSX2xvd2VyKSAvICgyICogMS45NiksCiAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDApLCB2ZXJib3NlID0gRgogICkpKQoKcGxvdDMuZmVtYWxlLm1ldGEuVlIgPC0gbWV0YWNvbWJvX2ZlbWFsZS5wbG90My5WUiAlPiUKICBtdXRhdGUobW9kZWxfbG5WUiA9IG1hcChkYXRhLCB+IG1ldGFmb3I6OnJtYS51bmkoCiAgICB5aSA9IC54JGxuVlIsIHNlaSA9ICgueCRsblZSX3VwcGVyIC0gLngkbG5WUl9sb3dlcikgLyAoMiAqIDEuOTYpLAogICAgY29udHJvbCA9IGxpc3Qob3B0aW1pemVyID0gIm9wdGltIiwgb3B0bWV0aG9kID0gIk5lbGRlci1NZWFkIiwgbWF4aXQgPSAxMDAwKSwgdmVyYm9zZSA9IEYKICApKSkKCnBsb3QzLmZlbWFsZS5tZXRhLlJSIDwtIG1ldGFjb21ib19mZW1hbGUucGxvdDMuUlIgJT4lCiAgbXV0YXRlKG1vZGVsX2xuUlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsblJSLCBzZWkgPSAoLngkbG5SUl91cHBlciAtIC54JGxuUlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgojIEFjcm9zcyBhbGwgZ3JvdXBpbmcgdGVybXMgIwoKcGxvdDMuZmVtYWxlLm1ldGEuQ1ZSLmFsbCA8LSBtZXRhY29tYm9fZmVtYWxlLnBsb3QzLkNWUi5hbGwgJT4lCiAgbXV0YXRlKG1vZGVsX2xuQ1ZSID0gbWFwKGRhdGEsIH4gbWV0YWZvcjo6cm1hLnVuaSgKICAgIHlpID0gLngkbG5DVlIsIHNlaSA9ICgueCRsbkNWUl91cHBlciAtIC54JGxuQ1ZSX2xvd2VyKSAvICgyICogMS45NiksCiAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDApLCB2ZXJib3NlID0gRgogICkpKQoKcGxvdDMuZmVtYWxlLm1ldGEuQ1ZSLmFsbCA8LSBwbG90My5mZW1hbGUubWV0YS5DVlIuYWxsICU+JSBtdXRhdGUoR3JvdXBpbmdUZXJtID0gIkFsbCIpCgpwbG90My5mZW1hbGUubWV0YS5WUi5hbGwgPC0gbWV0YWNvbWJvX2ZlbWFsZS5wbG90My5WUi5hbGwgJT4lCiAgbXV0YXRlKG1vZGVsX2xuVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsblZSLCBzZWkgPSAoLngkbG5WUl91cHBlciAtIC54JGxuVlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgpwbG90My5mZW1hbGUubWV0YS5WUi5hbGwgPC0gcGxvdDMuZmVtYWxlLm1ldGEuVlIuYWxsICU+JSBtdXRhdGUoR3JvdXBpbmdUZXJtID0gIkFsbCIpCgpwbG90My5mZW1hbGUubWV0YS5SUi5hbGwgPC0gbWV0YWNvbWJvX2ZlbWFsZS5wbG90My5SUi5hbGwgJT4lCiAgbXV0YXRlKG1vZGVsX2xuUlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsblJSLCBzZWkgPSAoLngkbG5SUl91cHBlciAtIC54JGxuUlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgpwbG90My5mZW1hbGUubWV0YS5SUi5hbGwgPC0gcGxvdDMuZmVtYWxlLm1ldGEuUlIuYWxsICU+JSBtdXRhdGUoR3JvdXBpbmdUZXJtID0gIkFsbCIpCgojIENvbWJpbmUgd2l0aCBzZXBhcmF0ZSBncm91cGluZyB0ZXJtIHJlc3VsdHMKCnBsb3QzLmZlbWFsZS5tZXRhLkNWUiA8LSBiaW5kX3Jvd3MocGxvdDMuZmVtYWxlLm1ldGEuQ1ZSLCBwbG90My5mZW1hbGUubWV0YS5DVlIuYWxsKQpwbG90My5mZW1hbGUubWV0YS5WUiA8LSBiaW5kX3Jvd3MocGxvdDMuZmVtYWxlLm1ldGEuVlIsIHBsb3QzLmZlbWFsZS5tZXRhLlZSLmFsbCkKcGxvdDMuZmVtYWxlLm1ldGEuUlIgPC0gYmluZF9yb3dzKHBsb3QzLmZlbWFsZS5tZXRhLlJSLCBwbG90My5mZW1hbGUubWV0YS5SUi5hbGwpCgojICoqUmUtc3RydWN0dXJlIGRhdGEgZm9yIGVhY2ggZ3JvdXBpbmcgdGVybTsgZGVsZXRlIHVuLXVzZWQgdmFyaWFibGVzCgpwbG90My5mZW1hbGUubWV0YS5DVlIuYiA8LSBhcy5kYXRhLmZyYW1lKHBsb3QzLmZlbWFsZS5tZXRhLkNWUiAlPiUgZ3JvdXBfYnkoR3JvdXBpbmdUZXJtKSAlPiUKICBtdXRhdGUoCiAgICBsbkNWUiA9IG1hcF9kYmwobW9kZWxfbG5DVlIsIHBsdWNrKDIpKSwgbG5DVlJfbG93ZXIgPSBtYXBfZGJsKG1vZGVsX2xuQ1ZSLCBwbHVjayg2KSksCiAgICBsbkNWUl91cHBlciA9IG1hcF9kYmwobW9kZWxfbG5DVlIsIHBsdWNrKDcpKSwgbG5DVlJfc2UgPSBtYXBfZGJsKG1vZGVsX2xuQ1ZSLCBwbHVjaygzKSkKICApKVssIGMoMSwgNDo3KV0KCmFkZC5yb3cuaGVhcmluZyA8LSBhcy5kYXRhLmZyYW1lKHQoYygiSGVhcmluZyIsIE5BLCBOQSwgTkEsIE5BKSkpICU+JSBzZXROYW1lcyhuYW1lcyhwbG90My5mZW1hbGUubWV0YS5DVlIuYikpCgpwbG90My5mZW1hbGUubWV0YS5DVlIuYiA8LSBiaW5kX3Jvd3MocGxvdDMuZmVtYWxlLm1ldGEuQ1ZSLmIsIGFkZC5yb3cuaGVhcmluZykKcGxvdDMuZmVtYWxlLm1ldGEuQ1ZSLmIgPC0gcGxvdDMuZmVtYWxlLm1ldGEuQ1ZSLmJbb3JkZXIocGxvdDMuZmVtYWxlLm1ldGEuQ1ZSLmIkR3JvdXBpbmdUZXJtKSwgXQoKcGxvdDMuZmVtYWxlLm1ldGEuVlIuYiA8LSBhcy5kYXRhLmZyYW1lKHBsb3QzLmZlbWFsZS5tZXRhLlZSICU+JSBncm91cF9ieShHcm91cGluZ1Rlcm0pICU+JQogIG11dGF0ZSgKICAgIGxuVlIgPSBtYXBfZGJsKG1vZGVsX2xuVlIsIHBsdWNrKDIpKSwgbG5WUl9sb3dlciA9IG1hcF9kYmwobW9kZWxfbG5WUiwgcGx1Y2soNikpLAogICAgbG5WUl91cHBlciA9IG1hcF9kYmwobW9kZWxfbG5WUiwgcGx1Y2soNykpLCBsblZSX3NlID0gbWFwX2RibChtb2RlbF9sblZSLCBwbHVjaygzKSkKICApKVssIGMoMSwgNDo3KV0KCnBsb3QzLmZlbWFsZS5tZXRhLlZSLmIgPC0gcGxvdDMuZmVtYWxlLm1ldGEuVlIuYltvcmRlcihwbG90My5mZW1hbGUubWV0YS5WUi5iJEdyb3VwaW5nVGVybSksIF0KCnBsb3QzLmZlbWFsZS5tZXRhLlJSLmIgPC0gYXMuZGF0YS5mcmFtZShwbG90My5mZW1hbGUubWV0YS5SUiAlPiUgZ3JvdXBfYnkoR3JvdXBpbmdUZXJtKSAlPiUKICBtdXRhdGUoCiAgICBsblJSID0gbWFwX2RibChtb2RlbF9sblJSLCBwbHVjaygyKSksIGxuUlJfbG93ZXIgPSBtYXBfZGJsKG1vZGVsX2xuUlIsIHBsdWNrKDYpKSwKICAgIGxuUlJfdXBwZXIgPSBtYXBfZGJsKG1vZGVsX2xuUlIsIHBsdWNrKDcpKSwgbG5SUl9zZSA9IG1hcF9kYmwobW9kZWxfbG5SUiwgcGx1Y2soMykpCiAgKSlbLCBjKDEsIDQ6NyldCgpwbG90My5mZW1hbGUubWV0YS5SUi5iIDwtIHBsb3QzLmZlbWFsZS5tZXRhLlJSLmJbb3JkZXIocGxvdDMuZmVtYWxlLm1ldGEuUlIuYiRHcm91cGluZ1Rlcm0pLCBdCgpvdmVyYWxsLmZlbWFsZS5wbG90MyA8LSBmdWxsX2pvaW4ocGxvdDMuZmVtYWxlLm1ldGEuQ1ZSLmIsIHBsb3QzLmZlbWFsZS5tZXRhLlZSLmIpCm92ZXJhbGwuZmVtYWxlLnBsb3QzIDwtIGZ1bGxfam9pbihvdmVyYWxsLmZlbWFsZS5wbG90MywgcGxvdDMuZmVtYWxlLm1ldGEuUlIuYikKCm92ZXJhbGwuZmVtYWxlLnBsb3QzJEdyb3VwaW5nVGVybSA8LSBmYWN0b3Iob3ZlcmFsbC5mZW1hbGUucGxvdDMkR3JvdXBpbmdUZXJtLCBsZXZlbHMgPSBjKCJCZWhhdmlvdXIiLCAiTW9ycGhvbG9neSIsICJNZXRhYm9saXNtIiwgIlBoeXNpb2xvZ3kiLCAiSW1tdW5vbG9neSIsICJIZW1hdG9sb2d5IiwgIkhlYXJ0IiwgIkhlYXJpbmciLCAiRXllIiwgIkFsbCIpKQpvdmVyYWxsLmZlbWFsZS5wbG90MyRHcm91cGluZ1Rlcm0gPC0gZmFjdG9yKG92ZXJhbGwuZmVtYWxlLnBsb3QzJEdyb3VwaW5nVGVybSwgcmV2KGxldmVscyhvdmVyYWxsLmZlbWFsZS5wbG90MyRHcm91cGluZ1Rlcm0pKSkKYGBgCgpSZXN0cnVjdHVyZSBkYXRhIGZvciBwbG90dGluZwoKYGBge3J9Cm92ZXJhbGwzLmZlbWFsZS5zaWcgPC0gZ2F0aGVyKG92ZXJhbGwuZmVtYWxlLnBsb3QzLCBwYXJhbWV0ZXIsIHZhbHVlLCBjKGxuQ1ZSLCBsblJSKSwgZmFjdG9yX2tleSA9IFRSVUUpICMgbG5WUiwKCmxuQ1ZSLmNpIDwtIG92ZXJhbGwzLmZlbWFsZS5zaWcgJT4lCiAgZmlsdGVyKHBhcmFtZXRlciA9PSAibG5DVlIiKSAlPiUKICBtdXRhdGUoY2kubG93ID0gbG5DVlJfbG93ZXIsIGNpLmhpZ2ggPSBsbkNWUl91cHBlcikKIyBsblZSLmNpIDwtIG92ZXJhbGwzLmZlbWFsZS5zaWcgICU+JSBmaWx0ZXIocGFyYW1ldGVyID09ICJsblZSIikgJT4lIG11dGF0ZShjaS5sb3cgPSBsblZSX2xvd2VyLCBjaS5oaWdoID0gbG5WUl91cHBlcikKbG5SUi5jaSA8LSBvdmVyYWxsMy5mZW1hbGUuc2lnICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImxuUlIiKSAlPiUKICBtdXRhdGUoY2kubG93ID0gbG5SUl9sb3dlciwgY2kuaGlnaCA9IGxuUlJfdXBwZXIpCgpvdmVyYWxsNC5mZW1hbGUuc2lnIDwtIGJpbmRfcm93cyhsbkNWUi5jaSwgbG5SUi5jaSkgJT4lIHNlbGVjdChHcm91cGluZ1Rlcm0sIHBhcmFtZXRlciwgdmFsdWUsIGNpLmxvdywgY2kuaGlnaCkgIyBsblZSLmNpLAoKb3ZlcmFsbDQuZmVtYWxlLnNpZyRsYWJlbCA8LSAiQ0kgbm90IG92ZXJsYXBwaW5nIHplcm8iCmBgYAoKUGxvdCBGaWc1QiBhbGwgc2lnbmlmaWNhbnQgcmVzdWx0cyAoQ0kgbm90IG92ZXJsYXBwaW5nIHplcm8sIGZlbWFsZSApCgpgYGB7cn0KCk1ldGFtZXRhX0ZpZzNfZmVtYWxlLnNpZyA8LSBvdmVyYWxsNC5mZW1hbGUuc2lnICU+JQogIGdncGxvdChhZXMoeSA9IEdyb3VwaW5nVGVybSwgeCA9IHZhbHVlKSkgKwogIGdlb21fZXJyb3JiYXJoKGFlcygKICAgIHhtaW4gPSBjaS5sb3csCiAgICB4bWF4ID0gY2kuaGlnaAogICksCiAgaGVpZ2h0ID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBwYXJhbWV0ZXIpLAogICAgZmlsbCA9ICJzYWxtb24xIiwgY29sb3IgPSAic2FsbW9uMSIsIHNpemUgPSAyLjIsCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbGltaXRzID0gYygtMC40LCAwKSwKICAgIGJyZWFrcyA9IGMoLTAuMywgMCksCiAgICBuYW1lID0gIkVmZmVjdCBzaXplIgogICkgKwogIGdlb21fdmxpbmUoCiAgICB4aW50ZXJjZXB0ID0gMCwKICAgIGNvbG9yID0gImJsYWNrIiwKICAgIGxpbmV0eXBlID0gImRhc2hlZCIKICApICsKICBmYWNldF9ncmlkKAogICAgY29scyA9IHZhcnMocGFyYW1ldGVyKSwgIyByb3dzID0gdmFycyhsYWJlbCksCiAgICAjIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSAyMyksCiAgICBzY2FsZXMgPSAiZnJlZSIsCiAgICBzcGFjZSA9ICJmcmVlIgogICkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjcwLCBzaXplID0gMTAsIG1hcmdpbiA9IG1hcmdpbih0ID0gMTUsIHIgPSAxNSwgYiA9IDE1LCBsID0gMTUpKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOVUxMLCBsaW5ldHlwZSA9ICJibGFuayIsIGZpbGwgPSAiZ3JheTkwIiksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgTWV0YW1ldGFfRmlnM19mZW1hbGUuc2lnIChGaWd1cmUgNUIgbGVmdCBwYW5lbCkKYGBgCgojIyMjIEZpZzUgRCA+MTAlCgpQcmVwYXJlIGRhdGEgZm9yIHRyYWl0cyB3aXRoIG0vZiBkaWZmZXJlbmNlID4gMTAlCgpjcmVhdGUgY29sdW1uIHdpdGggMT0gbGFyZ2VyLCAwPSBkaWZmIG5vdCBsYXJnZXIgdGhhbiAxMCUKCiMjIyMgTWFsZSBGaWcgNUQgPiAxMCUgKG1hbGUgYmlhc2VkIHRyYWl0cykKCmBgYHtyfQptZXRhLm1hbGUucGxvdDMucGVyYyA8LSBtZXRhY29tYm8gJT4lCiAgbXV0YXRlKAogICAgcGVyY0NWUiA9IGlmZWxzZShsbkNWUiA+IGxvZygxMSAvIDEwKSwgMSwgMCksCiAgICBwZXJjVlIgPSBpZmVsc2UobG5WUiA+IGxvZygxMSAvIDEwKSwgMSwgMCksCiAgICBwZXJjUlIgPSBpZmVsc2UobG5SUiA+IGxvZygxMSAvIDEwKSwgMSwgMCkKICApCgojIFNpZ25pZmljYW50IHN1YnNldCBmb3IgbG5DVlIKbWV0YWNvbWJvX21hbGUucGxvdDMuQ1ZSLnBlcmMgPC0gbWV0YS5tYWxlLnBsb3QzLnBlcmMgJT4lCiAgZmlsdGVyKHBlcmNDVlIgPT0gMSkgJT4lCiAgZ3JvdXBfYnkoR3JvdXBpbmdUZXJtKSAlPiUKICBuZXN0KCkKCm1ldGFjb21ib19tYWxlLnBsb3QzLkNWUi5wZXJjLmFsbCA8LSBtZXRhLm1hbGUucGxvdDMucGVyYyAlPiUKICBmaWx0ZXIocGVyY0NWUiA9PSAxKSAlPiUKICBuZXN0KCkKCiMgU2lnbmlmaWNhbnQgc3Vic2V0IGZvciBsblZSCm1ldGFjb21ib19tYWxlLnBsb3QzLlZSLnBlcmMgPC0gbWV0YS5tYWxlLnBsb3QzLnBlcmMgJT4lCiAgZmlsdGVyKHBlcmNWUiA9PSAxKSAlPiUKICBncm91cF9ieShHcm91cGluZ1Rlcm0pICU+JQogIG5lc3QoKQoKbWV0YWNvbWJvX21hbGUucGxvdDMuVlIucGVyYy5hbGwgPC0gbWV0YS5tYWxlLnBsb3QzLnBlcmMgJT4lCiAgZmlsdGVyKHBlcmNWUiA9PSAxKSAlPiUKICBuZXN0KCkKCiMgU2lnbmlmaWNhbnQgc3Vic2V0IGZvciBsblJSCm1ldGFjb21ib19tYWxlLnBsb3QzLlJSLnBlcmMgPC0gbWV0YS5tYWxlLnBsb3QzLnBlcmMgJT4lCiAgZmlsdGVyKHBlcmNSUiA9PSAxKSAlPiUKICBncm91cF9ieShHcm91cGluZ1Rlcm0pICU+JQogIG5lc3QoKQoKbWV0YWNvbWJvX21hbGUucGxvdDMuUlIucGVyYy5hbGwgPC0gbWV0YS5tYWxlLnBsb3QzLnBlcmMgJT4lCiAgZmlsdGVyKHBlcmNSUiA9PSAxKSAlPiUKICBuZXN0KCkKCgojICoqRmluYWwgZml4ZWQgZWZmZWN0cyBtZXRhLWFuYWx5c2VzIHdpdGhpbiBncm91cGluZyB0ZXJtcyBhbmQgYWNyb3NzIGdyb3VwaW5nIHRlcm1zLCB3aXRoIFNFIG9mIHRoZSBlc3RpbWF0ZQoKcGxvdDMubWFsZS5tZXRhLkNWUi5wZXJjIDwtIG1ldGFjb21ib19tYWxlLnBsb3QzLkNWUi5wZXJjICU+JQogIG11dGF0ZShtb2RlbF9sbkNWUiA9IG1hcChkYXRhLCB+IG1ldGFmb3I6OnJtYS51bmkoCiAgICB5aSA9IC54JGxuQ1ZSLCBzZWkgPSAoLngkbG5DVlJfdXBwZXIgLSAueCRsbkNWUl9sb3dlcikgLyAoMiAqIDEuOTYpLAogICAgY29udHJvbCA9IGxpc3Qob3B0aW1pemVyID0gIm9wdGltIiwgb3B0bWV0aG9kID0gIk5lbGRlci1NZWFkIiwgbWF4aXQgPSAxMDAwKSwgdmVyYm9zZSA9IEYKICApKSkKCnBsb3QzLm1hbGUubWV0YS5WUi5wZXJjIDwtIG1ldGFjb21ib19tYWxlLnBsb3QzLlZSLnBlcmMgJT4lCiAgbXV0YXRlKG1vZGVsX2xuVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsblZSLCBzZWkgPSAoLngkbG5WUl91cHBlciAtIC54JGxuVlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgpwbG90My5tYWxlLm1ldGEuUlIucGVyYyA8LSBtZXRhY29tYm9fbWFsZS5wbG90My5SUi5wZXJjICU+JQogIG11dGF0ZShtb2RlbF9sblJSID0gbWFwKGRhdGEsIH4gbWV0YWZvcjo6cm1hLnVuaSgKICAgIHlpID0gLngkbG5SUiwgc2VpID0gKC54JGxuUlJfdXBwZXIgLSAueCRsblJSX2xvd2VyKSAvICgyICogMS45NiksCiAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDApLCB2ZXJib3NlID0gRgogICkpKQoKIyBBY3Jvc3MgYWxsIGdyb3VwaW5nIHRlcm1zICMKCnBsb3QzLm1hbGUubWV0YS5DVlIucGVyYy5hbGwgPC0gbWV0YWNvbWJvX21hbGUucGxvdDMuQ1ZSLnBlcmMuYWxsICU+JQogIG11dGF0ZShtb2RlbF9sbkNWUiA9IG1hcChkYXRhLCB+IG1ldGFmb3I6OnJtYS51bmkoCiAgICB5aSA9IC54JGxuQ1ZSLCBzZWkgPSAoLngkbG5DVlJfdXBwZXIgLSAueCRsbkNWUl9sb3dlcikgLyAoMiAqIDEuOTYpLAogICAgY29udHJvbCA9IGxpc3Qob3B0aW1pemVyID0gIm9wdGltIiwgb3B0bWV0aG9kID0gIk5lbGRlci1NZWFkIiwgbWF4aXQgPSAxMDAwKSwgdmVyYm9zZSA9IEYKICApKSkKCnBsb3QzLm1hbGUubWV0YS5DVlIucGVyYy5hbGwgPC0gcGxvdDMubWFsZS5tZXRhLkNWUi5wZXJjLmFsbCAlPiUgbXV0YXRlKEdyb3VwaW5nVGVybSA9ICJBbGwiKQoKcGxvdDMubWFsZS5tZXRhLlZSLnBlcmMuYWxsIDwtIG1ldGFjb21ib19tYWxlLnBsb3QzLlZSLnBlcmMuYWxsICU+JQogIG11dGF0ZShtb2RlbF9sblZSID0gbWFwKGRhdGEsIH4gbWV0YWZvcjo6cm1hLnVuaSgKICAgIHlpID0gLngkbG5WUiwgc2VpID0gKC54JGxuVlJfdXBwZXIgLSAueCRsblZSX2xvd2VyKSAvICgyICogMS45NiksCiAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDApLCB2ZXJib3NlID0gRgogICkpKQoKcGxvdDMubWFsZS5tZXRhLlZSLnBlcmMuYWxsIDwtIHBsb3QzLm1hbGUubWV0YS5WUi5wZXJjLmFsbCAlPiUgbXV0YXRlKEdyb3VwaW5nVGVybSA9ICJBbGwiKQoKcGxvdDMubWFsZS5tZXRhLlJSLnBlcmMuYWxsIDwtIG1ldGFjb21ib19tYWxlLnBsb3QzLlJSLnBlcmMuYWxsICU+JQogIG11dGF0ZShtb2RlbF9sblJSID0gbWFwKGRhdGEsIH4gbWV0YWZvcjo6cm1hLnVuaSgKICAgIHlpID0gLngkbG5SUiwgc2VpID0gKC54JGxuUlJfdXBwZXIgLSAueCRsblJSX2xvd2VyKSAvICgyICogMS45NiksCiAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDApLCB2ZXJib3NlID0gRgogICkpKQoKcGxvdDMubWFsZS5tZXRhLlJSLnBlcmMuYWxsIDwtIHBsb3QzLm1hbGUubWV0YS5SUi5wZXJjLmFsbCAlPiUgbXV0YXRlKEdyb3VwaW5nVGVybSA9ICJBbGwiKQoKIyBDb21iaW5lIHdpdGggc2VwYXJhdGUgZ3JvdXBpbmcgdGVybSByZXN1bHRzCgpwbG90My5tYWxlLm1ldGEuQ1ZSLnBlcmMgPC0gYmluZF9yb3dzKHBsb3QzLm1hbGUubWV0YS5DVlIucGVyYywgcGxvdDMubWFsZS5tZXRhLkNWUi5wZXJjLmFsbCkKcGxvdDMubWFsZS5tZXRhLlZSLnBlcmMgPC0gYmluZF9yb3dzKHBsb3QzLm1hbGUubWV0YS5WUi5wZXJjLCBwbG90My5tYWxlLm1ldGEuVlIucGVyYy5hbGwpCnBsb3QzLm1hbGUubWV0YS5SUi5wZXJjIDwtIGJpbmRfcm93cyhwbG90My5tYWxlLm1ldGEuUlIucGVyYywgcGxvdDMubWFsZS5tZXRhLlJSLnBlcmMuYWxsKQoKCiMgKipSZS1zdHJ1Y3R1cmUgZGF0YSBmb3IgZWFjaCBncm91cGluZyB0ZXJtOyBkZWxldGUgdW4tdXNlZCB2YXJpYWJsZXM6ICJIZWFyaW5nIG1pc3NpbmcgZm9yIGFsbCAzIHBhcmFtZXRlcnMiCgpwbG90My5tYWxlLm1ldGEuQ1ZSLnBlcmMuYiA8LSBhcy5kYXRhLmZyYW1lKHBsb3QzLm1hbGUubWV0YS5DVlIucGVyYyAlPiUgZ3JvdXBfYnkoR3JvdXBpbmdUZXJtKSAlPiUKICBtdXRhdGUoCiAgICBsbkNWUiA9IG1hcF9kYmwobW9kZWxfbG5DVlIsIHBsdWNrKDIpKSwgbG5DVlJfbG93ZXIgPSBtYXBfZGJsKG1vZGVsX2xuQ1ZSLCBwbHVjayg2KSksCiAgICBsbkNWUl91cHBlciA9IG1hcF9kYmwobW9kZWxfbG5DVlIsIHBsdWNrKDcpKSwgbG5DVlJfc2UgPSBtYXBfZGJsKG1vZGVsX2xuQ1ZSLCBwbHVjaygzKSkKICApKVssIGMoMSwgNDo3KV0KYWRkLnJvdy5oZWFyaW5nIDwtIGFzLmRhdGEuZnJhbWUodChjKCJIZWFyaW5nIiwgTkEsIE5BLCBOQSwgTkEpKSkgJT4lIHNldE5hbWVzKG5hbWVzKHBsb3QzLm1hbGUubWV0YS5DVlIucGVyYy5iKSkKcGxvdDMubWFsZS5tZXRhLkNWUi5wZXJjLmIgPC0gcmJpbmQocGxvdDMubWFsZS5tZXRhLkNWUi5wZXJjLmIsIGFkZC5yb3cuaGVhcmluZykKcGxvdDMubWFsZS5tZXRhLkNWUi5wZXJjLmIgPC0gcGxvdDMubWFsZS5tZXRhLkNWUi5wZXJjLmJbb3JkZXIocGxvdDMubWFsZS5tZXRhLkNWUi5wZXJjLmIkR3JvdXBpbmdUZXJtKSwgXQoKcGxvdDMubWFsZS5tZXRhLlZSLnBlcmMuYiA8LSBhcy5kYXRhLmZyYW1lKHBsb3QzLm1hbGUubWV0YS5WUi5wZXJjICU+JSBncm91cF9ieShHcm91cGluZ1Rlcm0pICU+JQogIG11dGF0ZSgKICAgIGxuVlIgPSBtYXBfZGJsKG1vZGVsX2xuVlIsIHBsdWNrKDIpKSwgbG5WUl9sb3dlciA9IG1hcF9kYmwobW9kZWxfbG5WUiwgcGx1Y2soNikpLAogICAgbG5WUl91cHBlciA9IG1hcF9kYmwobW9kZWxfbG5WUiwgcGx1Y2soNykpLCBsblZSX3NlID0gbWFwX2RibChtb2RlbF9sblZSLCBwbHVjaygzKSkKICApKVssIGMoMSwgNDo3KV0KYWRkLnJvdy5oZWFyaW5nIDwtIGFzLmRhdGEuZnJhbWUodChjKCJIZWFyaW5nIiwgTkEsIE5BLCBOQSwgTkEpKSkgJT4lIHNldE5hbWVzKG5hbWVzKHBsb3QzLm1hbGUubWV0YS5WUi5wZXJjLmIpKQpwbG90My5tYWxlLm1ldGEuVlIucGVyYy5iIDwtIHJiaW5kKHBsb3QzLm1hbGUubWV0YS5WUi5wZXJjLmIsIGFkZC5yb3cuaGVhcmluZykKcGxvdDMubWFsZS5tZXRhLlZSLnBlcmMuYiA8LSBwbG90My5tYWxlLm1ldGEuVlIucGVyYy5iW29yZGVyKHBsb3QzLm1hbGUubWV0YS5WUi5wZXJjLmIkR3JvdXBpbmdUZXJtKSwgXQoKcGxvdDMubWFsZS5tZXRhLlJSLnBlcmMuYiA8LSBhcy5kYXRhLmZyYW1lKHBsb3QzLm1hbGUubWV0YS5SUi5wZXJjICU+JSBncm91cF9ieShHcm91cGluZ1Rlcm0pICU+JQogIG11dGF0ZSgKICAgIGxuUlIgPSBtYXBfZGJsKG1vZGVsX2xuUlIsIHBsdWNrKDIpKSwgbG5SUl9sb3dlciA9IG1hcF9kYmwobW9kZWxfbG5SUiwgcGx1Y2soNikpLAogICAgbG5SUl91cHBlciA9IG1hcF9kYmwobW9kZWxfbG5SUiwgcGx1Y2soNykpLCBsblJSX3NlID0gbWFwX2RibChtb2RlbF9sblJSLCBwbHVjaygzKSkKICApKVssIGMoMSwgNDo3KV0KYWRkLnJvdy5oZWFyaW5nIDwtIGFzLmRhdGEuZnJhbWUodChjKCJIZWFyaW5nIiwgTkEsIE5BLCBOQSwgTkEpKSkgJT4lCiAgc2V0TmFtZXMobmFtZXMocGxvdDMubWFsZS5tZXRhLlJSLnBlcmMuYikpCnBsb3QzLm1hbGUubWV0YS5SUi5wZXJjLmIgPC0gcmJpbmQocGxvdDMubWFsZS5tZXRhLlJSLnBlcmMuYiwgYWRkLnJvdy5oZWFyaW5nKQoKYWRkLnJvdy5leWUgPC0gYXMuZGF0YS5mcmFtZSh0KGMoIkV5ZSIsIE5BLCBOQSwgTkEsIE5BKSkpICU+JQogIHNldE5hbWVzKG5hbWVzKHBsb3QzLm1hbGUubWV0YS5SUi5wZXJjLmIpKQpwbG90My5tYWxlLm1ldGEuUlIucGVyYy5iIDwtIHJiaW5kKHBsb3QzLm1hbGUubWV0YS5SUi5wZXJjLmIsIGFkZC5yb3cuZXllKQoKcGxvdDMubWFsZS5tZXRhLlJSLnBlcmMuYiA8LSBwbG90My5tYWxlLm1ldGEuUlIucGVyYy5iW29yZGVyKHBsb3QzLm1hbGUubWV0YS5SUi5wZXJjLmIkR3JvdXBpbmdUZXJtKSwgXQoKcGxvdDMubWFsZS5tZXRhLkNWUi5Wci5wZXJjIDwtIGZ1bGxfam9pbihwbG90My5tYWxlLm1ldGEuQ1ZSLnBlcmMuYiwgcGxvdDMubWFsZS5tZXRhLlZSLnBlcmMuYikKb3ZlcmFsbC5tYWxlLnBsb3QzLnBlcmMgPC0gZnVsbF9qb2luKHBsb3QzLm1hbGUubWV0YS5DVlIuVnIucGVyYywgcGxvdDMubWFsZS5tZXRhLlJSLnBlcmMuYikKCgpvdmVyYWxsLm1hbGUucGxvdDMucGVyYyRHcm91cGluZ1Rlcm0gPC0gZmFjdG9yKG92ZXJhbGwubWFsZS5wbG90My5wZXJjJEdyb3VwaW5nVGVybSwgbGV2ZWxzID0gYygiQmVoYXZpb3VyIiwgIk1vcnBob2xvZ3kiLCAiTWV0YWJvbGlzbSIsICJQaHlzaW9sb2d5IiwgIkltbXVub2xvZ3kiLCAiSGVtYXRvbG9neSIsICJIZWFydCIsICJIZWFyaW5nIiwgIkV5ZSIsICJBbGwiKSkKb3ZlcmFsbC5tYWxlLnBsb3QzLnBlcmMkR3JvdXBpbmdUZXJtIDwtIGZhY3RvcihvdmVyYWxsLm1hbGUucGxvdDMucGVyYyRHcm91cGluZ1Rlcm0sIHJldihsZXZlbHMob3ZlcmFsbC5tYWxlLnBsb3QzLnBlcmMkR3JvdXBpbmdUZXJtKSkpCmBgYAoKUmVzdHJ1Y3R1cmUgZGF0YSBmb3IgcGxvdHRpbmcgOiBNYWxlIGJpYXNlZCwgMTAlIGRpZmZlcmVuY2UKCmBgYHtyfQpvdmVyYWxsMy5wZXJjIDwtIGdhdGhlcihvdmVyYWxsLm1hbGUucGxvdDMucGVyYywgcGFyYW1ldGVyLCB2YWx1ZSwgYyhsbkNWUiwgbG5SUiksIGZhY3Rvcl9rZXkgPSBUUlVFKSAjIGxuVlIsCgpsbkNWUi5jaSA8LSBvdmVyYWxsMy5wZXJjICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImxuQ1ZSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuQ1ZSX2xvd2VyLCBjaS5oaWdoID0gbG5DVlJfdXBwZXIpCiMgbG5WUi5jaSA8LSBvdmVyYWxsMy5wZXJjICAlPiUgZmlsdGVyKHBhcmFtZXRlciA9PSAibG5WUiIpICU+JSBtdXRhdGUoY2kubG93ID0gbG5WUl9sb3dlciwgY2kuaGlnaCA9IGxuVlJfdXBwZXIpCmxuUlIuY2kgPC0gb3ZlcmFsbDMucGVyYyAlPiUKICBmaWx0ZXIocGFyYW1ldGVyID09ICJsblJSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuUlJfbG93ZXIsIGNpLmhpZ2ggPSBsblJSX3VwcGVyKQoKb3ZlcmFsbDQubWFsZS5wZXJjIDwtIGJpbmRfcm93cyhsbkNWUi5jaSwgbG5SUi5jaSkgJT4lIHNlbGVjdChHcm91cGluZ1Rlcm0sIHBhcmFtZXRlciwgdmFsdWUsIGNpLmxvdywgY2kuaGlnaCkgIyBsblZSLmNpLAoKb3ZlcmFsbDQubWFsZS5wZXJjJGxhYmVsIDwtICJTZXggZGlmZmVyZW5jZSBpbiBtL2YgcmF0aW9zID4gMTAlIgoKb3ZlcmFsbDQubWFsZS5wZXJjJHZhbHVlIDwtIGFzLm51bWVyaWMob3ZlcmFsbDQubWFsZS5wZXJjJHZhbHVlKQpvdmVyYWxsNC5tYWxlLnBlcmMkY2kubG93IDwtIGFzLm51bWVyaWMob3ZlcmFsbDQubWFsZS5wZXJjJGNpLmxvdykKb3ZlcmFsbDQubWFsZS5wZXJjJGNpLmhpZ2ggPC0gYXMubnVtZXJpYyhvdmVyYWxsNC5tYWxlLnBlcmMkY2kuaGlnaCkKYGBgCgpQbG90IEZpZzVEICBhbGwgPjEwJSBkaWZmZXJlbmNlIChtYWxlIGJpYXMpCgpgYGB7cn0KCk1ldGFtZXRhX0ZpZzNfbWFsZS5wZXJjIDwtIG92ZXJhbGw0Lm1hbGUucGVyYyAlPiUgIyBmaWx0ZXIoLiwgR3JvdXBpbmdUZXJtICE9ICJIZWFyaW5nIikgJT4lCiAgZ2dwbG90KGFlcyh5ID0gR3JvdXBpbmdUZXJtLCB4ID0gdmFsdWUpKSArCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKAogICAgeG1pbiA9IGNpLmxvdywKICAgIHhtYXggPSBjaS5oaWdoCiAgKSwKICBoZWlnaHQgPSAwLjEsIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50KGFlcygKICAgIHNoYXBlID0gcGFyYW1ldGVyLAogICAgZmlsbCA9IHBhcmFtZXRlcgogICksCiAgY29sb3IgPSAibWVkaXVtYXF1YW1hcmluZSIsIHNpemUgPSAyLjIsCiAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIHNjYWxlX3hfY29udGludW91cygKICAgIGxpbWl0cyA9IGMoLTAuMiwgMC42MiksCiAgICBicmVha3MgPSBjKDAsIDAuMyksCiAgICBuYW1lID0gIkVmZmVjdCBzaXplIgogICkgKwogIGdlb21fdmxpbmUoCiAgICB4aW50ZXJjZXB0ID0gMCwKICAgIGNvbG9yID0gImJsYWNrIiwKICAgIGxpbmV0eXBlID0gImRhc2hlZCIKICApICsKICBmYWNldF9ncmlkKAogICAgY29scyA9IHZhcnMocGFyYW1ldGVyKSwgcm93cyA9IHZhcnMobGFiZWwpLAogICAgbGFiZWxsZXIgPSBsYWJlbF93cmFwX2dlbih3aWR0aCA9IDIzKSwKICAgIHNjYWxlcyA9ICJmcmVlIiwKICAgIHNwYWNlID0gImZyZWUiCiAgKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNzAsIHNpemUgPSAxMCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxNSwgciA9IDE1LCBiID0gMTUsIGwgPSAxNSkpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOVUxMLCBsaW5ldHlwZSA9ICJibGFuayIsIGZpbGwgPSAiZ3JheTkwIiksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0KSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgTWV0YW1ldGFfRmlnM19tYWxlLnBlcmMgKEZpZ3VyZSA1RCByaWdodCBwYW5lbCkKYGBgCgojIyMjIEZlbWFsZSBGaWcgNUQgPjEwJQoKYGBge3J9CgptZXRhLnBsb3QzLnBlcmMgPC0gbWV0YWNvbWJvICU+JQogIG11dGF0ZSgKICAgIHBlcmNDVlIgPSBpZmVsc2UobG5DVlIgPCBsb2coOSAvIDEwKSwgMSwgMCksCiAgICBwZXJjVlIgPSBpZmVsc2UobG5WUiA8IGxvZyg5IC8gMTApLCAxLCAwKSwKICAgIHBlcmNSUiA9IGlmZWxzZShsblJSIDwgbG9nKDkgLyAxMCksIDEsIDApCiAgKQoKIyBTaWduaWZpY2FudCBzdWJzZXQgZm9yIGxuQ1ZSCm1ldGFjb21ib19wbG90My5DVlIucGVyYyA8LSBtZXRhLnBsb3QzLnBlcmMgJT4lCiAgZmlsdGVyKHBlcmNDVlIgPT0gMSkgJT4lCiAgZ3JvdXBfYnkoR3JvdXBpbmdUZXJtKSAlPiUKICBuZXN0KCkKCm1ldGFjb21ib19wbG90My5DVlIucGVyYy5hbGwgPC0gbWV0YS5wbG90My5wZXJjICU+JQogIGZpbHRlcihwZXJjQ1ZSID09IDEpICU+JQogIG5lc3QoKQoKIyBTaWduaWZpY2FudCBzdWJzZXQgZm9yIGxuVlIKbWV0YWNvbWJvX3Bsb3QzLlZSLnBlcmMgPC0gbWV0YS5wbG90My5wZXJjICU+JQogIGZpbHRlcihwZXJjVlIgPT0gMSkgJT4lCiAgZ3JvdXBfYnkoR3JvdXBpbmdUZXJtKSAlPiUKICBuZXN0KCkKCm1ldGFjb21ib19wbG90My5WUi5wZXJjLmFsbCA8LSBtZXRhLnBsb3QzLnBlcmMgJT4lCiAgZmlsdGVyKHBlcmNWUiA9PSAxKSAlPiUKICBuZXN0KCkKCiMgU2lnbmlmaWNhbnQgc3Vic2V0IGZvciBsblJSCm1ldGFjb21ib19wbG90My5SUi5wZXJjIDwtIG1ldGEucGxvdDMucGVyYyAlPiUKICBmaWx0ZXIocGVyY1JSID09IDEpICU+JQogIGdyb3VwX2J5KEdyb3VwaW5nVGVybSkgJT4lCiAgbmVzdCgpCgptZXRhY29tYm9fcGxvdDMuUlIucGVyYy5hbGwgPC0gbWV0YS5wbG90My5wZXJjICU+JQogIGZpbHRlcihwZXJjUlIgPT0gMSkgJT4lCiAgbmVzdCgpCgoKIyAqKkZpbmFsIGZpeGVkIGVmZmVjdHMgbWV0YS1hbmFseXNlcyB3aXRoaW4gZ3JvdXBpbmcgdGVybXMsIHdpdGggU0Ugb2YgdGhlIGVzdGltYXRlCgpwbG90My5tZXRhLkNWUi5wZXJjIDwtIG1ldGFjb21ib19wbG90My5DVlIucGVyYyAlPiUKICBtdXRhdGUobW9kZWxfbG5DVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsbkNWUiwgc2VpID0gKC54JGxuQ1ZSX3VwcGVyIC0gLngkbG5DVlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgpwbG90My5tZXRhLlZSLnBlcmMgPC0gbWV0YWNvbWJvX3Bsb3QzLlZSLnBlcmMgJT4lCiAgbXV0YXRlKG1vZGVsX2xuVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsblZSLCBzZWkgPSAoLngkbG5WUl91cHBlciAtIC54JGxuVlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgpwbG90My5tZXRhLlJSLnBlcmMgPC0gbWV0YWNvbWJvX3Bsb3QzLlJSLnBlcmMgJT4lCiAgbXV0YXRlKG1vZGVsX2xuUlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsblJSLCBzZWkgPSAoLngkbG5SUl91cHBlciAtIC54JGxuUlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgojIEFjcm9zcyBhbGwgZ3JvdXBpbmcgdGVybXMgIwoKcGxvdDMubWV0YS5DVlIucGVyYy5hbGwgPC0gbWV0YWNvbWJvX3Bsb3QzLkNWUi5wZXJjLmFsbCAlPiUKICBtdXRhdGUobW9kZWxfbG5DVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsbkNWUiwgc2VpID0gKC54JGxuQ1ZSX3VwcGVyIC0gLngkbG5DVlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgpwbG90My5tZXRhLkNWUi5wZXJjLmFsbCA8LSBwbG90My5tZXRhLkNWUi5wZXJjLmFsbCAlPiUgbXV0YXRlKEdyb3VwaW5nVGVybSA9ICJBbGwiKQoKcGxvdDMubWV0YS5WUi5wZXJjLmFsbCA8LSBtZXRhY29tYm9fcGxvdDMuVlIucGVyYy5hbGwgJT4lCiAgbXV0YXRlKG1vZGVsX2xuVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgeWkgPSAueCRsblZSLCBzZWkgPSAoLngkbG5WUl91cHBlciAtIC54JGxuVlJfbG93ZXIpIC8gKDIgKiAxLjk2KSwKICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIHZlcmJvc2UgPSBGCiAgKSkpCgpwbG90My5tZXRhLlZSLnBlcmMuYWxsIDwtIHBsb3QzLm1ldGEuVlIucGVyYy5hbGwgJT4lIG11dGF0ZShHcm91cGluZ1Rlcm0gPSAiQWxsIikKCnBsb3QzLm1ldGEuUlIucGVyYy5hbGwgPC0gbWV0YWNvbWJvX3Bsb3QzLlJSLnBlcmMuYWxsICU+JQogIG11dGF0ZShtb2RlbF9sblJSID0gbWFwKGRhdGEsIH4gbWV0YWZvcjo6cm1hLnVuaSgKICAgIHlpID0gLngkbG5SUiwgc2VpID0gKC54JGxuUlJfdXBwZXIgLSAueCRsblJSX2xvd2VyKSAvICgyICogMS45NiksCiAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDApLCB2ZXJib3NlID0gRgogICkpKQoKcGxvdDMubWV0YS5SUi5wZXJjLmFsbCA8LSBwbG90My5tZXRhLlJSLnBlcmMuYWxsICU+JSBtdXRhdGUoR3JvdXBpbmdUZXJtID0gIkFsbCIpCgojIENvbWJpbmUgd2l0aCBzZXBhcmF0ZSBncm91cGluZyB0ZXJtIHJlc3VsdHMKCnBsb3QzLm1ldGEuQ1ZSLnBlcmMgPC0gYmluZF9yb3dzKHBsb3QzLm1ldGEuQ1ZSLnBlcmMsIHBsb3QzLm1ldGEuQ1ZSLnBlcmMuYWxsKQpwbG90My5tZXRhLlZSLnBlcmMgPC0gYmluZF9yb3dzKHBsb3QzLm1ldGEuVlIucGVyYywgcGxvdDMubWV0YS5WUi5wZXJjLmFsbCkKcGxvdDMubWV0YS5SUi5wZXJjIDwtIGJpbmRfcm93cyhwbG90My5tZXRhLlJSLnBlcmMsIHBsb3QzLm1ldGEuUlIucGVyYy5hbGwpCgoKIyAqKlJlLXN0cnVjdHVyZSBkYXRhIGZvciBlYWNoIGdyb3VwaW5nIHRlcm07IGRlbGV0ZSB1bi11c2VkIHZhcmlhYmxlczogIkhlYXJpbmcgbWlzc2luZyBmb3IgYWxsIDMgcGFyYW1ldGVycyIKCnBsb3QzLm1ldGEuQ1ZSLnBlcmMuYiA8LSBhcy5kYXRhLmZyYW1lKHBsb3QzLm1ldGEuQ1ZSLnBlcmMgJT4lIGdyb3VwX2J5KEdyb3VwaW5nVGVybSkgJT4lCiAgbXV0YXRlKAogICAgbG5DVlIgPSBtYXBfZGJsKG1vZGVsX2xuQ1ZSLCBwbHVjaygyKSksIGxuQ1ZSX2xvd2VyID0gbWFwX2RibChtb2RlbF9sbkNWUiwgcGx1Y2soNikpLAogICAgbG5DVlJfdXBwZXIgPSBtYXBfZGJsKG1vZGVsX2xuQ1ZSLCBwbHVjayg3KSksIGxuQ1ZSX3NlID0gbWFwX2RibChtb2RlbF9sbkNWUiwgcGx1Y2soMykpCiAgKSlbLCBjKDEsIDQ6NyldCmFkZC5yb3cuaGVhcmluZyA8LSBhcy5kYXRhLmZyYW1lKHQoYygiSGVhcmluZyIsIE5BLCBOQSwgTkEsIE5BKSkpICU+JSBzZXROYW1lcyhuYW1lcyhwbG90My5tZXRhLkNWUi5wZXJjLmIpKQpwbG90My5tZXRhLkNWUi5wZXJjLmIgPC0gcmJpbmQocGxvdDMubWV0YS5DVlIucGVyYy5iLCBhZGQucm93LmhlYXJpbmcpCnBsb3QzLm1ldGEuQ1ZSLnBlcmMuYiA8LSBwbG90My5tZXRhLkNWUi5wZXJjLmJbb3JkZXIocGxvdDMubWV0YS5DVlIucGVyYy5iJEdyb3VwaW5nVGVybSksIF0KCnBsb3QzLm1ldGEuVlIucGVyYy5iIDwtIGFzLmRhdGEuZnJhbWUocGxvdDMubWV0YS5WUi5wZXJjICU+JSBncm91cF9ieShHcm91cGluZ1Rlcm0pICU+JQogIG11dGF0ZSgKICAgIGxuVlIgPSBtYXBfZGJsKG1vZGVsX2xuVlIsIHBsdWNrKDIpKSwgbG5WUl9sb3dlciA9IG1hcF9kYmwobW9kZWxfbG5WUiwgcGx1Y2soNikpLAogICAgbG5WUl91cHBlciA9IG1hcF9kYmwobW9kZWxfbG5WUiwgcGx1Y2soNykpLCBsblZSX3NlID0gbWFwX2RibChtb2RlbF9sblZSLCBwbHVjaygzKSkKICApKVssIGMoMSwgNDo3KV0KYWRkLnJvdy5oZWFyaW5nIDwtIGFzLmRhdGEuZnJhbWUodChjKCJIZWFyaW5nIiwgTkEsIE5BLCBOQSwgTkEpKSkgJT4lIHNldE5hbWVzKG5hbWVzKHBsb3QzLm1ldGEuVlIucGVyYy5iKSkKcGxvdDMubWV0YS5WUi5wZXJjLmIgPC0gcmJpbmQocGxvdDMubWV0YS5WUi5wZXJjLmIsIGFkZC5yb3cuaGVhcmluZykKcGxvdDMubWV0YS5WUi5wZXJjLmIgPC0gcGxvdDMubWV0YS5WUi5wZXJjLmJbb3JkZXIocGxvdDMubWV0YS5WUi5wZXJjLmIkR3JvdXBpbmdUZXJtKSwgXQoKcGxvdDMubWV0YS5SUi5wZXJjLmIgPC0gYXMuZGF0YS5mcmFtZShwbG90My5tZXRhLlJSLnBlcmMgJT4lIGdyb3VwX2J5KEdyb3VwaW5nVGVybSkgJT4lCiAgbXV0YXRlKAogICAgbG5SUiA9IG1hcF9kYmwobW9kZWxfbG5SUiwgcGx1Y2soMikpLCBsblJSX2xvd2VyID0gbWFwX2RibChtb2RlbF9sblJSLCBwbHVjayg2KSksCiAgICBsblJSX3VwcGVyID0gbWFwX2RibChtb2RlbF9sblJSLCBwbHVjayg3KSksIGxuUlJfc2UgPSBtYXBfZGJsKG1vZGVsX2xuUlIsIHBsdWNrKDMpKQogICkpWywgYygxLCA0OjcpXQphZGQucm93LmhlYXJpbmcgPC0gYXMuZGF0YS5mcmFtZSh0KGMoIkhlYXJpbmciLCBOQSwgTkEsIE5BLCBOQSkpKSAlPiUgc2V0TmFtZXMobmFtZXMocGxvdDMubWV0YS5SUi5wZXJjLmIpKQpwbG90My5tZXRhLlJSLnBlcmMuYiA8LSByYmluZChwbG90My5tZXRhLlJSLnBlcmMuYiwgYWRkLnJvdy5oZWFyaW5nKQphZGQucm93LmhlbWF0b2xvZ3kgPC0gYXMuZGF0YS5mcmFtZSh0KGMoIkhlbWF0b2xvZ3kiLCBOQSwgTkEsIE5BLCBOQSkpKSAlPiUKICBzZXROYW1lcyhuYW1lcyhwbG90My5tZXRhLlJSLnBlcmMuYikpCnBsb3QzLm1ldGEuUlIucGVyYy5iIDwtIHJiaW5kKHBsb3QzLm1ldGEuUlIucGVyYy5iLCBhZGQucm93LmhlbWF0b2xvZ3kpCgoKcGxvdDMubWV0YS5SUi5wZXJjLmIgPC0gcGxvdDMubWV0YS5SUi5wZXJjLmJbb3JkZXIocGxvdDMubWV0YS5SUi5wZXJjLmIkR3JvdXBpbmdUZXJtKSwgXQoKcGxvdDMubWV0YS5DVlIucGVyYy5jIDwtIGZ1bGxfam9pbihwbG90My5tZXRhLkNWUi5wZXJjLmIsIHBsb3QzLm1ldGEuVlIucGVyYy5iKQpvdmVyYWxsLnBsb3QzLnBlcmMgPC0gZnVsbF9qb2luKHBsb3QzLm1ldGEuQ1ZSLnBlcmMuYywgcGxvdDMubWV0YS5SUi5wZXJjLmIpCgoKb3ZlcmFsbC5wbG90My5wZXJjJEdyb3VwaW5nVGVybSA8LSBmYWN0b3Iob3ZlcmFsbC5wbG90My5wZXJjJEdyb3VwaW5nVGVybSwgbGV2ZWxzID0gYygiQmVoYXZpb3VyIiwgIk1vcnBob2xvZ3kiLCAiTWV0YWJvbGlzbSIsICJQaHlzaW9sb2d5IiwgIkltbXVub2xvZ3kiLCAiSGVtYXRvbG9neSIsICJIZWFydCIsICJIZWFyaW5nIiwgIkV5ZSIsICJBbGwiKSkKb3ZlcmFsbC5wbG90My5wZXJjJEdyb3VwaW5nVGVybSA8LSBmYWN0b3Iob3ZlcmFsbC5wbG90My5wZXJjJEdyb3VwaW5nVGVybSwgcmV2KGxldmVscyhvdmVyYWxsLnBsb3QzLnBlcmMkR3JvdXBpbmdUZXJtKSkpCmBgYAoKUmVzdHJ1Y3R1cmUgZGF0YSBmb3IgcGxvdHRpbmcKRmVtYWxlIGJpYXMsIDEwIHBlcmNlbnQgZGlmZmVyZW5jZQoKYGBge3J9Cm92ZXJhbGwzLnBlcmMgPC0gZ2F0aGVyKG92ZXJhbGwucGxvdDMucGVyYywgcGFyYW1ldGVyLCB2YWx1ZSwgYyhsbkNWUiwgbG5SUiksIGZhY3Rvcl9rZXkgPSBUUlVFKSAjIGxuVlIsCgpsbkNWUi5jaSA8LSBvdmVyYWxsMy5wZXJjICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImxuQ1ZSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuQ1ZSX2xvd2VyLCBjaS5oaWdoID0gbG5DVlJfdXBwZXIpCiMgbG5WUi5jaSA8LSBvdmVyYWxsMy5wZXJjICAlPiUgZmlsdGVyKHBhcmFtZXRlciA9PSAibG5WUiIpICU+JSBtdXRhdGUoY2kubG93ID0gbG5WUl9sb3dlciwgY2kuaGlnaCA9IGxuVlJfdXBwZXIpCmxuUlIuY2kgPC0gb3ZlcmFsbDMucGVyYyAlPiUKICBmaWx0ZXIocGFyYW1ldGVyID09ICJsblJSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuUlJfbG93ZXIsIGNpLmhpZ2ggPSBsblJSX3VwcGVyKQoKb3ZlcmFsbDQucGVyYyA8LSBiaW5kX3Jvd3MobG5DVlIuY2ksIGxuUlIuY2kpICU+JSBzZWxlY3QoR3JvdXBpbmdUZXJtLCBwYXJhbWV0ZXIsIHZhbHVlLCBjaS5sb3csIGNpLmhpZ2gpICMgbG5WUi5jaSwKCm92ZXJhbGw0LnBlcmMkbGFiZWwgPC0gIlNleCBkaWZmZXJlbmNlIGluIG0vZiByYXRpb3MgPiAxMCUiCgpvdmVyYWxsNC5wZXJjJHZhbHVlIDwtIGFzLm51bWVyaWMob3ZlcmFsbDQucGVyYyR2YWx1ZSkKb3ZlcmFsbDQucGVyYyRjaS5sb3cgPC0gYXMubnVtZXJpYyhvdmVyYWxsNC5wZXJjJGNpLmxvdykKb3ZlcmFsbDQucGVyYyRjaS5oaWdoIDwtIGFzLm51bWVyaWMob3ZlcmFsbDQucGVyYyRjaS5oaWdoKQpgYGAKClBsb3QgRmlnNUQgYWxsID4xMCUgZGlmZmVyZW5jZSAoZmVtYWxlKQoKYGBge3J9Ck1ldGFtZXRhX0ZpZzNfZmVtYWxlLnBlcmMgPC0gb3ZlcmFsbDQucGVyYyAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBHcm91cGluZ1Rlcm0sIHggPSB2YWx1ZSkpICsKICBnZW9tX2Vycm9yYmFyaChhZXMoCiAgICB4bWluID0gY2kubG93LAogICAgeG1heCA9IGNpLmhpZ2gKICApLAogIGhlaWdodCA9IDAuMSwgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIGdlb21fcG9pbnQoYWVzKHNoYXBlID0gcGFyYW1ldGVyKSwKICAgIGZpbGwgPSAic2FsbW9uMSIsIGNvbG9yID0gInNhbG1vbjEiLCBzaXplID0gMi4yLAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwoKICAjIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPQoKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBsaW1pdHMgPSBjKC0wLjUzLCAwLjIpLAogICAgYnJlYWtzID0gYygtMC4zLCAwKSwKICAgIG5hbWUgPSAiRWZmZWN0IHNpemUiCiAgKSArCiAgZ2VvbV92bGluZSgKICAgIHhpbnRlcmNlcHQgPSAwLAogICAgY29sb3IgPSAiYmxhY2siLAogICAgbGluZXR5cGUgPSAiZGFzaGVkIgogICkgKwogIGZhY2V0X2dyaWQoCiAgICBjb2xzID0gdmFycyhwYXJhbWV0ZXIpLCAjIHJvd3MgPSB2YXJzKGxhYmVsKSwKICAgICMgbGFiZWxsZXIgPSBsYWJlbF93cmFwX2dlbih3aWR0aCA9IDIzKSwKICAgIHNjYWxlcyA9ICJmcmVlIiwKICAgIHNwYWNlID0gImZyZWUiCiAgKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNzAsIHNpemUgPSAxMCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxNSwgciA9IDE1LCBiID0gMTUsIGwgPSAxNSkpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOVUxMLCBsaW5ldHlwZSA9ICJibGFuayIsIGZpbGwgPSAiZ3JheTkwIiksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0KSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgTWV0YW1ldGFfRmlnM19mZW1hbGUucGVyYyAoRmlndXJlIDVEIGxlZnQgcGFuZWwpCmBgYAoKIyMjIyBQbG90IEZpZzU6ICAgcGxvdHMgY29tYmluZWQKCmBgYHtyfQpsaWJyYXJ5KGdncHVicikKRmlnNWIgPC0gZ2dhcnJhbmdlKE1ldGFtZXRhX0ZpZzNfZmVtYWxlLnNpZywgTWV0YW1ldGFfRmlnM19tYWxlLnNpZywKICBuY29sID0gMiwgbnJvdyA9IDEsIHdpZHRocyA9IGMoMSwgMS4yMCksIGhlaWdodHMgPSBjKDEsIDEpCikKCkZpZzVkIDwtIGdnYXJyYW5nZShNZXRhbWV0YV9GaWczX2ZlbWFsZS5wZXJjLCBNZXRhbWV0YV9GaWczX21hbGUucGVyYywKICBuY29sID0gMiwgbnJvdyA9IDEsIHdpZHRocyA9IGMoMSwgMS4yMCksIGhlaWdodHMgPSBjKDEsIDEpCikKCiMgZW5kIGNvbWJpbmF0aW9uIEZpZ3VyZSA1CgpGaWc1IDwtIGdnYXJyYW5nZShtYWxlYmlhc19GaWcyX3NpZ3RyYWl0cywgbWFsZWJpYXNfRmlnMl9vdmVyMTAsIEZpZzViLCBGaWc1ZCwgbmNvbCA9IDEsIG5yb3cgPSA0LCBoZWlnaHRzID0gYygyLjMsIDIsIDIuMSwgMiksIGxhYmVscyA9IGMoIkEiLCAiICIsICJCIiwgIiAiKSkKRmlnNQpgYGAKCgojIyBIZXRlcm9nZW5laXR5CiMjIyMgRklHVVJFIDQgKFNlY29uZC1vcmRlciBtZXRhIGFuYWx5c2lzIG9uIGhldGVyb2dlbmVpdHkpCkNyZWF0ZSBtYXRyaXggdG8gc3RvcmUgcmVzdWx0cyBmb3IgYWxsIHRyYWl0cwoKYGBge3J9CnJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQoYygxOm4pLCBtYXRyaXgocmVwKDAsIG4gKiAzMCksIG5jb2wgPSAzMCkpKQpuYW1lcyhyZXN1bHRzLmFsbGhldGVyby5ncm91cGluZykgPC0gYygKICAiaWQiLCAic2lnbWEyX3N0cmFpbi5DVlIiLCAic2lnbWEyX2NlbnRlci5DVlIiLCAic2lnbWEyX2Vycm9yLkNWUiIsICJzLm5sZXZlbHMuc3RyYWluLkNWUiIsCiAgInMubmxldmVscy5jZW50ZXIuQ1ZSIiwgInMubmxldmVscy5lcnJvci5DVlIiLCAic2lnbWEyX3N0cmFpbi5WUiIsICJzaWdtYTJfY2VudGVyLlZSIiwgInNpZ21hMl9lcnJvci5WUiIsICJzLm5sZXZlbHMuc3RyYWluLlZSIiwKICAicy5ubGV2ZWxzLmNlbnRlci5WUiIsICJzLm5sZXZlbHMuZXJyb3IuVlIiLCAic2lnbWEyX3N0cmFpbi5SUiIsICJzaWdtYTJfY2VudGVyLlJSIiwgInNpZ21hMl9lcnJvci5SUiIsICJzLm5sZXZlbHMuc3RyYWluLlJSIiwKICAicy5ubGV2ZWxzLmNlbnRlci5SUiIsICJzLm5sZXZlbHMuZXJyb3IuUlIiLCAibG5DVlIiLCAibG5DVlJfbG93ZXIiLCAibG5DVlJfdXBwZXIiLCAibG5DVlJfc2UiLCAibG5WUiIsICJsblZSX2xvd2VyIiwgImxuVlJfdXBwZXIiLAogICJsblZSX3NlIiwgImxuUlIiLCAibG5SUl9sb3dlciIsICJsblJSX3VwcGVyIiwgImxuUlJfc2UiCikKYGBgCgpMT09QClBhcmFtZXRlcnMgdG8gZXh0cmFjdCBmcm9tIG1ldGFmb3IgKHNpZ21hMidzLCBzLm5sZXZlbHMpCgpgYGB7cn0KCmZvciAodCBpbiAxOm4pIHsKICB0cnlDYXRjaCgKICAgIHsKICAgICAgZGF0YV9wYXJfYWdlIDwtIGRhdGFfc3Vic2V0X3BhcmFtZXRlcmlkX2luZGl2aWR1YWxfYnlfYWdlKGRhdGEsIHQsIGFnZV9taW4gPSAwLCBhZ2VfY2VudGVyID0gMTAwKQoKICAgICAgcG9wdWxhdGlvbl9zdGF0cyA8LSBjYWxjdWxhdGVfcG9wdWxhdGlvbl9zdGF0cyhkYXRhX3Bhcl9hZ2UpCgogICAgICByZXN1bHRzIDwtIGNyZWF0ZV9tZXRhX2FuYWx5c2lzX2VmZmVjdF9zaXplcyhwb3B1bGF0aW9uX3N0YXRzKQoKICAgICAgIyBsbkNWUiwgbG9nYXJpdG0gb2YgdGhlIHJhdGlvIG9mIG1hbGUgYW5kIGZlbWFsZSBjb2VmZmljaWVudHMgb2YgdmFyaWFuY2UKCiAgICAgIGN2ci4gPC0gbWV0YWZvcjo6cm1hLm12KHlpID0gZWZmZWN0X3NpemVfQ1ZSLCBWID0gc2FtcGxlX3ZhcmlhbmNlX0NWUiwgcmFuZG9tID0gbGlzdCgKICAgICAgICB+IDEgfCBzdHJhaW5fbmFtZSwgfiAxIHwgcHJvZHVjdGlvbl9jZW50ZXIsCiAgICAgICAgfiAxIHwgZXJyCiAgICAgICksIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIGRhdGEgPSByZXN1bHRzKQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAyXSA8LSBjdnIuJHNpZ21hMlsxXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAzXSA8LSBjdnIuJHNpZ21hMlsyXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCA0XSA8LSBjdnIuJHNpZ21hMlszXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCA1XSA8LSBjdnIuJHMubmxldmVsc1sxXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCA2XSA8LSBjdnIuJHMubmxldmVsc1syXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCA3XSA8LSBjdnIuJHMubmxldmVsc1szXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAyMF0gPC0gY3ZyLiRiCiAgICAgIHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nW3QsIDIxXSA8LSBjdnIuJGNpLmxiCiAgICAgIHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nW3QsIDIyXSA8LSBjdnIuJGNpLnViCiAgICAgIHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nW3QsIDIzXSA8LSBjdnIuJHNlCgogICAgICAjIGxuVlIsIG1hbGUgdG8gZmVtYWxlIHZhcmlhYmlsaXR5IHJhdGlvIChsb2dhcml0aG0gb2YgbWFsZSBhbmQgZmVtYWxlIHN0YW5kYXJkIGRldmlhdGlvbnMpCgogICAgICB2ci4gPC0gbWV0YWZvcjo6cm1hLm12KHlpID0gZWZmZWN0X3NpemVfVlIsIFYgPSBzYW1wbGVfdmFyaWFuY2VfVlIsIHJhbmRvbSA9IGxpc3QoCiAgICAgICAgfiAxIHwgc3RyYWluX25hbWUsIH4gMSB8IHByb2R1Y3Rpb25fY2VudGVyLAogICAgICAgIH4gMSB8IGVycgogICAgICApLCBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDApLCBkYXRhID0gcmVzdWx0cykKICAgICAgcmVzdWx0cy5hbGxoZXRlcm8uZ3JvdXBpbmdbdCwgOF0gPC0gdnIuJHNpZ21hMlsxXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCA5XSA8LSB2ci4kc2lnbWEyWzJdCiAgICAgIHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nW3QsIDEwXSA8LSB2ci4kc2lnbWEyWzNdCiAgICAgIHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nW3QsIDExXSA8LSB2ci4kcy5ubGV2ZWxzWzFdCiAgICAgIHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nW3QsIDEyXSA8LSB2ci4kcy5ubGV2ZWxzWzJdCiAgICAgIHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nW3QsIDEzXSA8LSB2ci4kcy5ubGV2ZWxzWzNdCiAgICAgIHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nW3QsIDI0XSA8LSB2ci4kYgogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAyNV0gPC0gdnIuJGNpLmxiCiAgICAgIHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nW3QsIDI2XSA8LSB2ci4kY2kudWIKICAgICAgcmVzdWx0cy5hbGxoZXRlcm8uZ3JvdXBpbmdbdCwgMjddIDwtIHZyLiRzZQoKICAgICAgIyBsblJSLCByZXNwb25zZSByYXRpbyAobG9nYXJpdGhtIG9mIG1hbGUgYW5kIGZlbWFsZSBtZWFucykKCiAgICAgIHJyLiA8LSBtZXRhZm9yOjpybWEubXYoeWkgPSBlZmZlY3Rfc2l6ZV9SUiwgViA9IHNhbXBsZV92YXJpYW5jZV9SUiwgcmFuZG9tID0gbGlzdCgKICAgICAgICB+IDEgfCBzdHJhaW5fbmFtZSwgfiAxIHwgcHJvZHVjdGlvbl9jZW50ZXIsCiAgICAgICAgfiAxIHwgZXJyCiAgICAgICksIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplciA9ICJvcHRpbSIsIG9wdG1ldGhvZCA9ICJOZWxkZXItTWVhZCIsIG1heGl0ID0gMTAwMCksIGRhdGEgPSByZXN1bHRzKQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAxNF0gPC0gcnIuJHNpZ21hMlsxXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAxNV0gPC0gcnIuJHNpZ21hMlsyXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAxNl0gPC0gcnIuJHNpZ21hMlszXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAxN10gPC0gcnIuJHMubmxldmVsc1sxXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAxOF0gPC0gcnIuJHMubmxldmVsc1syXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAxOV0gPC0gcnIuJHMubmxldmVsc1szXQogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAyOF0gPC0gcnIuJGIKICAgICAgcmVzdWx0cy5hbGxoZXRlcm8uZ3JvdXBpbmdbdCwgMjldIDwtIHJyLiRjaS5sYgogICAgICByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1t0LCAzMF0gPC0gcnIuJGNpLnViCiAgICAgIHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nW3QsIDMxXSA8LSByci4kc2UKICAgIH0sCiAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICAgICAgY2F0KCJFUlJPUiA6IiwgY29uZGl0aW9uTWVzc2FnZShlKSwgIlxuIikKICAgIH0KICApCn0KYGBgCgojIyMjIEV4Y2x1ZGUgdHJhaXRzLCBtZXJnZSBkYXRhc2V0cwoKYGBge3J9CnJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nMiA8LSByZXN1bHRzLmFsbGhldGVyby5ncm91cGluZ1tyZXN1bHRzLmFsbGhldGVyby5ncm91cGluZyRzLm5sZXZlbHMuc3RyYWluLlZSICE9IDAsIF0KIyBucm93KHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nMikgIzIxOApgYGAKCk1lcmdlIGRhdGEgc2V0cyBjb250YWluaW5nIG1ldGFmb3IgcmVzdWx0cyB3aXRoIHByb2NlZHVyZSBldGMuIG5hbWVzIAoKYGBge3J9CiMgcHJvY2VkdXJlcyA8LSByZWFkLmNzdihoZXJlKCJleHBvcnQiLCAicHJvY2VkdXJlcy5jc3YiKSkKCnJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nMiRwYXJhbWV0ZXJfZ3JvdXAgPC0gZGF0YSRwYXJhbWV0ZXJfZ3JvdXBbbWF0Y2gocmVzdWx0cy5hbGxoZXRlcm8uZ3JvdXBpbmcyJGlkLCBkYXRhJGlkKV0KcmVzdWx0cy5hbGxoZXRlcm8uZ3JvdXBpbmcyJHByb2NlZHVyZSA8LSBkYXRhJHByb2NlZHVyZV9uYW1lW21hdGNoKHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nMiRpZCwgZGF0YSRpZCldCgpyZXN1bHRzLmFsbGhldGVyby5ncm91cGluZzIkR3JvdXBpbmdUZXJtIDwtIHByb2NlZHVyZXMkR3JvdXBpbmdUZXJtW21hdGNoKHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nMiRwcm9jZWR1cmUsIHByb2NlZHVyZXMkcHJvY2VkdXJlKV0KcmVzdWx0cy5hbGxoZXRlcm8uZ3JvdXBpbmcyJHBhcmFtZXRlcl9uYW1lIDwtIGRhdGEkcGFyYW1ldGVyX25hbWVbbWF0Y2gocmVzdWx0cy5hbGxoZXRlcm8uZ3JvdXBpbmcyJGlkLCBkYXRhJGlkKV0KYGBgCgojIyMjIENvcnJlbGF0ZWQgcGFyYW1ldGVycwoKYGBge3J9Cm1ldGFoZXRlcm8xIDwtIHJlc3VsdHMuYWxsaGV0ZXJvLmdyb3VwaW5nMgojIGxlbmd0aCh1bmlxdWUobWV0YWhldGVybzEkcHJvY2VkdXJlKSkgIzE4CiMgbGVuZ3RoKHVuaXF1ZShtZXRhaGV0ZXJvMSRHcm91cGluZ1Rlcm0pKSAjOQojIGxlbmd0aCh1bmlxdWUobWV0YWhldGVybzEkcGFyYW1ldGVyX2dyb3VwKSkgIyAxNDkKIyBsZW5ndGgodW5pcXVlKG1ldGFoZXRlcm8xJHBhcmFtZXRlcl9uYW1lKSkgIzIxOAoKIyBDb3VudCBvZiBudW1iZXIgb2YgcGFyYW1ldGVyIG5hbWVzIChjb3JyZWxhdGVkIHN1Yi10cmFpdHMpIGluIGVhY2ggcGFyYW1ldGVyIGdyb3VwIChwYXJfZ3JvdXBfc2l6ZSkKCm1ldGFoZXRlcm8xYiA8LQogIG1ldGFoZXRlcm8xICU+JQogIGdyb3VwX2J5KHBhcmFtZXRlcl9ncm91cCkgJT4lCiAgbXV0YXRlKHBhcl9ncm91cF9zaXplID0gbl9kaXN0aW5jdChwYXJhbWV0ZXJfbmFtZSkpCgptZXRhaGV0ZXJvMSRwYXJfZ3JvdXBfc2l6ZSA8LSBtZXRhaGV0ZXJvMWIkcGFyX2dyb3VwX3NpemVbbWF0Y2gobWV0YWhldGVybzEkcGFyYW1ldGVyX2dyb3VwLCBtZXRhaGV0ZXJvMWIkcGFyYW1ldGVyX2dyb3VwKV0KCiMgQ3JlYXRlIHN1YnNldHMgd2l0aCA+IDEgY291bnQgKHBhcl9ncm91cF9zaXplID4gMSkKCm1ldGFoZXRlcm8xX3N1YiA8LSBzdWJzZXQobWV0YWhldGVybzEsIHBhcl9ncm91cF9zaXplID4gMSkgIyA5MCBvYnNlcnZhdGlvbnMKIyBzdHIobWV0YWhldGVybzFfc3ViKQojIG1ldGFoZXRlcm8xX3N1YiRzYW1wbGVTaXplIDwtIGFzLm51bWVyaWMobWV0YWhldGVybzFfc3ViJHNhbXBsZVNpemUpICNmcm9tIHByZXZpb3VzIGFuYWx5c2lzPyBkb24ndCB0aGluayBpcyB1c2VkOiA6IGRlbGV0ZSBpbiBmaW5hbCB2ZXJzaW9uCgojIE5lc3QgZGF0YQoKbl9jb3VudC4gPC0gbWV0YWhldGVybzFfc3ViICU+JQogIGdyb3VwX2J5KHBhcmFtZXRlcl9ncm91cCkgJT4lCiAgIyBtdXRhdGUocmF3X04gPSBzdW0oc2FtcGxlU2l6ZSkpICU+JSAgI2Rvbid0IHRoaW5rIGlzIG5lY2Vzc2FyeTogZGVsZXRlIGluIGZpbmFsIHZlcnNpb24KICBuZXN0KCkKCiMgbWV0YS1hbmFseXNpcyBwcmVwYXJhdGlvbgoKbW9kZWxfY291bnQuIDwtIG5fY291bnQuICU+JQogIG11dGF0ZSgKICAgIG1vZGVsX2xuUlIgPSBtYXAoZGF0YSwgfiByb2J1KC54JGxuUlIgfiAxLAogICAgICBkYXRhID0gLngsIHN0dWR5bnVtID0gLngkaWQsIG1vZGVsd2VpZ2h0cyA9IGMoIkNPUlIiKSwgcmhvID0gMC44LAogICAgICBzbWFsbCA9IFRSVUUsIHZhci5lZmYuc2l6ZSA9ICgueCRsblJSX3NlKV4yCiAgICApKSwKICAgIG1vZGVsX2xuVlIgPSBtYXAoZGF0YSwgfiByb2J1KC54JGxuVlIgfiAxLAogICAgICBkYXRhID0gLngsIHN0dWR5bnVtID0gLngkaWQsIG1vZGVsd2VpZ2h0cyA9IGMoIkNPUlIiKSwgcmhvID0gMC44LAogICAgICBzbWFsbCA9IFRSVUUsIHZhci5lZmYuc2l6ZSA9ICgueCRsblZSX3NlKV4yCiAgICApKSwKICAgIG1vZGVsX2xuQ1ZSID0gbWFwKGRhdGEsIH4gcm9idSgueCRsbkNWUiB+IDEsCiAgICAgIGRhdGEgPSAueCwgc3R1ZHludW0gPSAueCRpZCwgbW9kZWx3ZWlnaHRzID0gYygiQ09SUiIpLCByaG8gPSAwLjgsCiAgICAgIHNtYWxsID0gVFJVRSwgdmFyLmVmZi5zaXplID0gKC54JGxuQ1ZSX3NlKV4yCiAgICApKQogICkKCgojIFJvYnVtZXRhIG9iamVjdCBkZXRhaWxzOgojIHN0cihtb2RlbF9jb3VudC4kbW9kZWxfbG5DVlJbWzFdXSkKCiMjICpQZXJmb3JtIG1ldGEtYW5hbHlzZXMgb24gY29ycmVsYXRlZCBzdWItdHJhaXRzLCB1c2luZyByb2J1bWV0YQoKIyBTaGluaWNoaTogV2UgdGhpbmsgd2Ugd2FudCB0byB1c2UgdGhlc2UgZm9yIGZ1cnRoZXIgYW5hbHlzZXM6CiMgcmVzaWR1YWwgdmFyaWFuY2U6IGFzLm51bWVyaWMocm9idV9maXQkbW9kX2luZm8kdGVybTEpICAgICAoc2FtZSBhcyAnbW9kX2luZm8kdGF1LnNxJykKIyBzYW1wbGUgc2l6ZTogcm9idV9maXQkTgoKIyMgKipFeHRyYWN0IGFuZCBzYXZlIHBhcmFtZXRlciBlc3RpbWF0ZXMKCmNvdW50X2Z1bi4gPC0gZnVuY3Rpb24obW9kX3N1YikgewogIHJldHVybihjKGFzLm51bWVyaWMobW9kX3N1YiRtb2RfaW5mbyR0ZXJtMSksIG1vZF9zdWIkTikpCn0KCnJvYnVzdWJfUlIuIDwtIG1vZGVsX2NvdW50LiAlPiUKICB0cmFuc211dGUocGFyYW1ldGVyX2dyb3VwLCBlc3RpbWF0ZWxuUlIgPSBtYXAobW9kZWxfbG5SUiwgY291bnRfZnVuLikpICU+JQogIG11dGF0ZShyID0gbWFwKGVzdGltYXRlbG5SUiwgfiBkYXRhLmZyYW1lKHQoLikpKSkgJT4lCiAgdW5uZXN0KHIpICU+JQogIHNlbGVjdCgtZXN0aW1hdGVsblJSKSAlPiUKICBwdXJycjo6c2V0X25hbWVzKGMoInBhcmFtZXRlcl9ncm91cCIsICJ2YXIuUlIiLCAiTi5SUiIpKQoKcm9idXN1Yl9DVlIuIDwtIG1vZGVsX2NvdW50LiAlPiUKICB0cmFuc211dGUocGFyYW1ldGVyX2dyb3VwLCBlc3RpbWF0ZWxuQ1ZSID0gbWFwKG1vZGVsX2xuQ1ZSLCBjb3VudF9mdW4uKSkgJT4lCiAgbXV0YXRlKHIgPSBtYXAoZXN0aW1hdGVsbkNWUiwgfiBkYXRhLmZyYW1lKHQoLikpKSkgJT4lCiAgdW5uZXN0KHIpICU+JQogIHNlbGVjdCgtZXN0aW1hdGVsbkNWUikgJT4lCiAgcHVycnI6OnNldF9uYW1lcyhjKCJwYXJhbWV0ZXJfZ3JvdXAiLCAidmFyLkNWUiIsICJOLkNWUiIpKQoKcm9idXN1Yl9WUi4gPC0gbW9kZWxfY291bnQuICU+JQogIHRyYW5zbXV0ZShwYXJhbWV0ZXJfZ3JvdXAsIGVzdGltYXRlbG5WUiA9IG1hcChtb2RlbF9sblZSLCBjb3VudF9mdW4uKSkgJT4lCiAgbXV0YXRlKHIgPSBtYXAoZXN0aW1hdGVsblZSLCB+IGRhdGEuZnJhbWUodCguKSkpKSAlPiUKICB1bm5lc3QocikgJT4lCiAgc2VsZWN0KC1lc3RpbWF0ZWxuVlIpICU+JQogIHB1cnJyOjpzZXRfbmFtZXMoYygicGFyYW1ldGVyX2dyb3VwIiwgInZhci5WUiIsICJOLlZSIikpCgpyb2J1X2FsbC4gPC0gZnVsbF9qb2luKHJvYnVzdWJfQ1ZSLiwgcm9idXN1Yl9WUi4pICU+JSBmdWxsX2pvaW4oLiwgcm9idXN1Yl9SUi4pCmBgYAoKTWVyZ2UgdGhlIHR3byBkYXRhIHNldHMgKHRoZSBuZXcgW3JvYnVfYWxsLl0gYW5kIHRoZSBpbml0aWFsIFt1bmNvcnJlbGF0ZWQgc3ViLXRyYWl0cyB3aXRoIGNvdW50ID0gMV0pCgpJbiB0aGlzIHN0ZXAsIHdlIAkKMSkgbWVyZ2UgdGhlIE4gZnJvbSByb2J1bWV0YSBhbmQgdGhlICBOIGZyb20gbWV0YWZvciAocy5ubGV2ZWxzLmVycm9yKSB0b2dldGhlciBpbnRvIHRoZSBzYW1lIGNvbHVtbnMgKE4uUlIsIE4uVlIsIE4uQ1ZSKQoyKSBjYWxjdWxhdGUgdGhlIHRvdGFsIHZhcmlhbmNlIGZvciBtZXRhZm9yIG1vZGVscyBhcyB0aGUgc3VtIG9mIHJhbmRvbSBlZmZlY3QgdmFyaWFuY2VzIGFuZCB0aGUgcmVzaWR1YWwgZXJyb3IsIHRoZW4gYWRkIGluIHRoZSBzYW1lIGNvbHVtbnMgdG9nZXRoZXIgd2l0aCB0aGUgcmVzaWR1YWwgdmFyaWFuY2VzIGZyb20gcm9idW1ldGEKCmBgYHtyfQptZXRhaGV0ZXJvX2FsbCA8LSBtZXRhaGV0ZXJvMSAlPiUKICBmaWx0ZXIocGFyX2dyb3VwX3NpemUgPT0gMSkgJT4lCiAgYXNfdGliYmxlKCkKbWV0YWhldGVyb19hbGwkTi5SUiA8LSBtZXRhaGV0ZXJvX2FsbCRzLm5sZXZlbHMuZXJyb3IuUlIKbWV0YWhldGVyb19hbGwkTi5DVlIgPC0gbWV0YWhldGVyb19hbGwkcy5ubGV2ZWxzLmVycm9yLkNWUgptZXRhaGV0ZXJvX2FsbCROLlZSIDwtIG1ldGFoZXRlcm9fYWxsJHMubmxldmVscy5lcnJvci5WUgptZXRhaGV0ZXJvX2FsbCR2YXIuUlIgPC0gbG9nKHNxcnQobWV0YWhldGVyb19hbGwkc2lnbWEyX3N0cmFpbi5SUiArIG1ldGFoZXRlcm9fYWxsJHNpZ21hMl9jZW50ZXIuUlIgKyBtZXRhaGV0ZXJvX2FsbCRzaWdtYTJfZXJyb3IuUlIpKQptZXRhaGV0ZXJvX2FsbCR2YXIuVlIgPC0gbG9nKHNxcnQobWV0YWhldGVyb19hbGwkc2lnbWEyX3N0cmFpbi5WUiArIG1ldGFoZXRlcm9fYWxsJHNpZ21hMl9jZW50ZXIuVlIgKyBtZXRhaGV0ZXJvX2FsbCRzaWdtYTJfZXJyb3IuVlIpKQptZXRhaGV0ZXJvX2FsbCR2YXIuQ1ZSIDwtIGxvZyhzcXJ0KG1ldGFoZXRlcm9fYWxsJHNpZ21hMl9zdHJhaW4uQ1ZSICsgbWV0YWhldGVyb19hbGwkc2lnbWEyX2NlbnRlci5DVlIgKyBtZXRhaGV0ZXJvX2FsbCRzaWdtYTJfZXJyb3IuQ1ZSKSkKIyBzdHIobWV0YWhldGVyb19hbGwpCiMgc3RyKHJvYnVfYWxsLikKCm1ldGFoZXRlcm9fYWxsIDwtIG1ldGFoZXRlcm9fYWxsICU+JSBtdXRhdGUoCiAgdmFyLlJSID0gaWZfZWxzZSh2YXIuUlIgPT0gLUluZiwgLTcsIHZhci5SUiksCiAgdmFyLlZSID0gaWZfZWxzZSh2YXIuVlIgPT0gLUluZiwgLTUsIHZhci5WUiksCiAgdmFyLkNWUiA9IGlmX2Vsc2UodmFyLkNWUiA9PSAtSW5mLCAtNiwgdmFyLkNWUikKKQoKIyAqKkNvbWJpbmUgZGF0YQojIyBTdGVwMQpjb21iaW5lZG1ldGFoZXRlcm8gPC0gYmluZF9yb3dzKHJvYnVfYWxsLiwgbWV0YWhldGVyb19hbGwpCiMgZ2xpbXBzZShjb21iaW5lZG1ldGFoZXRlcm8pCgojIFN0ZXBzIDImMwoKbWV0YWNvbWJvaGV0ZXJvIDwtIGNvbWJpbmVkbWV0YWhldGVybwptZXRhY29tYm9oZXRlcm8kY291bnRzIDwtIG1ldGFoZXRlcm8xJHBhcl9ncm91cF9zaXplW21hdGNoKG1ldGFjb21ib2hldGVybyRwYXJhbWV0ZXJfZ3JvdXAsIG1ldGFoZXRlcm8xJHBhcmFtZXRlcl9ncm91cCldCm1ldGFjb21ib2hldGVybyRwcm9jZWR1cmUyIDwtIG1ldGFoZXRlcm8xJHByb2NlZHVyZVttYXRjaChtZXRhY29tYm9oZXRlcm8kcGFyYW1ldGVyX2dyb3VwLCBtZXRhaGV0ZXJvMSRwYXJhbWV0ZXJfZ3JvdXApXQptZXRhY29tYm9oZXRlcm8kR3JvdXBpbmdUZXJtMiA8LSBtZXRhaGV0ZXJvMSRHcm91cGluZ1Rlcm1bbWF0Y2gobWV0YWNvbWJvaGV0ZXJvJHBhcmFtZXRlcl9ncm91cCwgbWV0YWhldGVybzEkcGFyYW1ldGVyX2dyb3VwKV0KCiMgKipDbGVhbi11cCBhbmQgcmVuYW1lCgptZXRhY29tYm9oZXRlcm8gPC0gbWV0YWNvbWJvaGV0ZXJvWywgYygxOjcsIDQzOjQ1KV0KbmFtZXMobWV0YWNvbWJvaGV0ZXJvKVs5XSA8LSAicHJvY2VkdXJlIgpuYW1lcyhtZXRhY29tYm9oZXRlcm8pWzEwXSA8LSAiR3JvdXBpbmdUZXJtIgpgYGAKCiMjIyMgTWV0YS1hbmFseXNpcyBvZiBoZXRlcm9nZW5laXR5CgpgYGB7cn0KIyMgKlBlcmZvcm0gbWV0YS1tZXRhLWFuYWx5c2lzICgzIGZvciBlYWNoIG9mIHRoZSA5IGdyb3VwaW5nIHRlcm1zOiB2YXIuQ1ZSLCB2YXIuVlIsIHZhci5SUikKCm1ldGFjb21ib2hldGVyb19maW5hbCA8LSBtZXRhY29tYm9oZXRlcm8gJT4lCiAgZ3JvdXBfYnkoR3JvdXBpbmdUZXJtKSAlPiUKICBuZXN0KCkKCiMgRmluYWwgZml4ZWQgZWZmZWN0cyBtZXRhLWFuYWx5c2VzIHdpdGhpbiBncm91cGluZyB0ZXJtcywgd2l0aCBTRSBvZiB0aGUgZXN0aW1hdGUKCiMgbWV0YWNvbWJvaGV0ZXJvJHZhci5DVlIKCmhldGVyb2cxIDwtIG1ldGFjb21ib2hldGVyb19maW5hbCAlPiUKCiAgbXV0YXRlKAogICAgbW9kZWxfaGV0ZXJvQ1ZSID0gbWFwKGRhdGEsIH4gbWV0YWZvcjo6cm1hLnVuaSgKICAgICAgeWkgPSAueCR2YXIuQ1ZSLCBzZWkgPSBzcXJ0KDEgLyAyICogKC54JE4uQ1ZSIC0gMSkpLAogICAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDAwLCBzdGVwYWRqID0gMC41KSwgdmVyYm9zZSA9IEYKICAgICkpLAogICAgbW9kZWxfaGV0ZXJvVlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgICB5aSA9IC54JHZhci5WUiwgc2VpID0gc3FydCgxIC8gMiAqICgueCROLlZSIC0gMSkpLAogICAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDAwLCBzdGVwYWRqID0gMC41KSwgdmVyYm9zZSA9IEYKICAgICkpLAogICAgbW9kZWxfaGV0ZXJvUlIgPSBtYXAoZGF0YSwgfiBtZXRhZm9yOjpybWEudW5pKAogICAgICB5aSA9IC54JHZhci5SUiwgc2VpID0gc3FydCgxIC8gMiAqICgueCROLlJSIC0gMSkpLAogICAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXIgPSAib3B0aW0iLCBvcHRtZXRob2QgPSAiTmVsZGVyLU1lYWQiLCBtYXhpdCA9IDEwMDAwLCBzdGVwYWRqID0gMC41KSwgdmVyYm9zZSA9IEYKICAgICkpCiAgKQoKCiMgKipSZS1zdHJ1Y3R1cmUgZGF0YSBmb3IgZWFjaCBncm91cGluZyB0ZXJtOyBleHRyYWN0IGhldGVyb2dlbmVuaXR5L3ZhcmlhbmNlIHRlcm1zOyBkZWxldGUgdW4tdXNlZCB2YXJpYWJsZXMKCkJlaGF2aW91ci4gPC0gaGV0ZXJvZzEgJT4lCiAgZmlsdGVyKC4sIEdyb3VwaW5nVGVybSA9PSAiQmVoYXZpb3VyIikgJT4lCiAgc2VsZWN0KC4sIC1kYXRhKSAlPiUKICBtdXRhdGUoCiAgICBoZXRlcm9DVlIgPSAuW1syXV1bWzFdXSRiLCBoZXRlcm9DVlJfbG93ZXIgPSAuW1syXV1bWzFdXSRjaS5sYiwgaGV0ZXJvQ1ZSX3VwcGVyID0gLltbMl1dW1sxXV0kY2kudWIsIGhldGVyb0NWUl9zZSA9IC5bWzJdXVtbMV1dJHNlLAogICAgaGV0ZXJvVlIgPSAuW1szXV1bWzFdXSRiLCBoZXRlcm9WUl9sb3dlciA9IC5bWzNdXVtbMV1dJGNpLmxiLCBoZXRlcm9WUl91cHBlciA9IC5bWzNdXVtbMV1dJGNpLnViLCBoZXRlcm9WUl9zZSA9IC5bWzNdXVtbMV1dJHNlLAogICAgaGV0ZXJvUlIgPSAuW1s0XV1bWzFdXSRiLCBoZXRlcm9SUl9sb3dlciA9IC5bWzRdXVtbMV1dJGNpLmxiLCBoZXRlcm9SUl91cHBlciA9IC5bWzRdXVtbMV1dJGNpLnViLCBoZXRlcm9SUl9zZSA9IC5bWzRdXVtbMV1dJHNlCiAgKSAlPiUKICBzZWxlY3QoLiwgR3JvdXBpbmdUZXJtLCBoZXRlcm9DVlI6aGV0ZXJvUlJfc2UpCgpJbW11bm9sb2d5LiA8LSBoZXRlcm9nMSAlPiUKICBmaWx0ZXIoLiwgR3JvdXBpbmdUZXJtID09ICJJbW11bm9sb2d5IikgJT4lCiAgc2VsZWN0KC4sIC1kYXRhKSAlPiUKICBtdXRhdGUoCiAgICBoZXRlcm9DVlIgPSAuW1syXV1bWzFdXSRiLCBoZXRlcm9DVlJfbG93ZXIgPSAuW1syXV1bWzFdXSRjaS5sYiwgaGV0ZXJvQ1ZSX3VwcGVyID0gLltbMl1dW1sxXV0kY2kudWIsIGhldGVyb0NWUl9zZSA9IC5bWzJdXVtbMV1dJHNlLAogICAgaGV0ZXJvVlIgPSAuW1szXV1bWzFdXSRiLCBoZXRlcm9WUl9sb3dlciA9IC5bWzNdXVtbMV1dJGNpLmxiLCBoZXRlcm9WUl91cHBlciA9IC5bWzNdXVtbMV1dJGNpLnViLCBoZXRlcm9WUl9zZSA9IC5bWzNdXVtbMV1dJHNlLAogICAgaGV0ZXJvUlIgPSAuW1s0XV1bWzFdXSRiLCBoZXRlcm9SUl9sb3dlciA9IC5bWzRdXVtbMV1dJGNpLmxiLCBoZXRlcm9SUl91cHBlciA9IC5bWzRdXVtbMV1dJGNpLnViLCBoZXRlcm9SUl9zZSA9IC5bWzRdXVtbMV1dJHNlCiAgKSAlPiUKICBzZWxlY3QoLiwgR3JvdXBpbmdUZXJtLCBoZXRlcm9DVlI6aGV0ZXJvUlJfc2UpCgoKSGVtYXRvbG9neS4gPC0gaGV0ZXJvZzEgJT4lCiAgZmlsdGVyKC4sIEdyb3VwaW5nVGVybSA9PSAiSGVtYXRvbG9neSIpICU+JQogIHNlbGVjdCguLCAtZGF0YSkgJT4lCiAgbXV0YXRlKAogICAgaGV0ZXJvQ1ZSID0gLltbMl1dW1sxXV0kYiwgaGV0ZXJvQ1ZSX2xvd2VyID0gLltbMl1dW1sxXV0kY2kubGIsIGhldGVyb0NWUl91cHBlciA9IC5bWzJdXVtbMV1dJGNpLnViLCBoZXRlcm9DVlJfc2UgPSAuW1syXV1bWzFdXSRzZSwKICAgIGhldGVyb1ZSID0gLltbM11dW1sxXV0kYiwgaGV0ZXJvVlJfbG93ZXIgPSAuW1szXV1bWzFdXSRjaS5sYiwgaGV0ZXJvVlJfdXBwZXIgPSAuW1szXV1bWzFdXSRjaS51YiwgaGV0ZXJvVlJfc2UgPSAuW1szXV1bWzFdXSRzZSwKICAgIGhldGVyb1JSID0gLltbNF1dW1sxXV0kYiwgaGV0ZXJvUlJfbG93ZXIgPSAuW1s0XV1bWzFdXSRjaS5sYiwgaGV0ZXJvUlJfdXBwZXIgPSAuW1s0XV1bWzFdXSRjaS51YiwgaGV0ZXJvUlJfc2UgPSAuW1s0XV1bWzFdXSRzZQogICkgJT4lCiAgc2VsZWN0KC4sIEdyb3VwaW5nVGVybSwgaGV0ZXJvQ1ZSOmhldGVyb1JSX3NlKQoKCkhlYXJpbmcuIDwtIGhldGVyb2cxICU+JQogIGZpbHRlciguLCBHcm91cGluZ1Rlcm0gPT0gIkhlYXJpbmciKSAlPiUKICBzZWxlY3QoLiwgLWRhdGEpICU+JQogIG11dGF0ZSgKICAgIGhldGVyb0NWUiA9IC5bWzJdXVtbMV1dJGIsIGhldGVyb0NWUl9sb3dlciA9IC5bWzJdXVtbMV1dJGNpLmxiLCBoZXRlcm9DVlJfdXBwZXIgPSAuW1syXV1bWzFdXSRjaS51YiwgaGV0ZXJvQ1ZSX3NlID0gLltbMl1dW1sxXV0kc2UsCiAgICBoZXRlcm9WUiA9IC5bWzNdXVtbMV1dJGIsIGhldGVyb1ZSX2xvd2VyID0gLltbM11dW1sxXV0kY2kubGIsIGhldGVyb1ZSX3VwcGVyID0gLltbM11dW1sxXV0kY2kudWIsIGhldGVyb1ZSX3NlID0gLltbM11dW1sxXV0kc2UsCiAgICBoZXRlcm9SUiA9IC5bWzRdXVtbMV1dJGIsIGhldGVyb1JSX2xvd2VyID0gLltbNF1dW1sxXV0kY2kubGIsIGhldGVyb1JSX3VwcGVyID0gLltbNF1dW1sxXV0kY2kudWIsIGhldGVyb1JSX3NlID0gLltbNF1dW1sxXV0kc2UKICApICU+JQogIHNlbGVjdCguLCBHcm91cGluZ1Rlcm0sIGhldGVyb0NWUjpoZXRlcm9SUl9zZSkKClBoeXNpb2xvZ3kuIDwtIGhldGVyb2cxICU+JQogIGZpbHRlciguLCBHcm91cGluZ1Rlcm0gPT0gIlBoeXNpb2xvZ3kiKSAlPiUKICBzZWxlY3QoLiwgLWRhdGEpICU+JQogIG11dGF0ZSgKICAgIGhldGVyb0NWUiA9IC5bWzJdXVtbMV1dJGIsIGhldGVyb0NWUl9sb3dlciA9IC5bWzJdXVtbMV1dJGNpLmxiLCBoZXRlcm9DVlJfdXBwZXIgPSAuW1syXV1bWzFdXSRjaS51YiwgaGV0ZXJvQ1ZSX3NlID0gLltbMl1dW1sxXV0kc2UsCiAgICBoZXRlcm9WUiA9IC5bWzNdXVtbMV1dJGIsIGhldGVyb1ZSX2xvd2VyID0gLltbM11dW1sxXV0kY2kubGIsIGhldGVyb1ZSX3VwcGVyID0gLltbM11dW1sxXV0kY2kudWIsIGhldGVyb1ZSX3NlID0gLltbM11dW1sxXV0kc2UsCiAgICBoZXRlcm9SUiA9IC5bWzRdXVtbMV1dJGIsIGhldGVyb1JSX2xvd2VyID0gLltbNF1dW1sxXV0kY2kubGIsIGhldGVyb1JSX3VwcGVyID0gLltbNF1dW1sxXV0kY2kudWIsIGhldGVyb1JSX3NlID0gLltbNF1dW1sxXV0kc2UKICApICU+JQogIHNlbGVjdCguLCBHcm91cGluZ1Rlcm0sIGhldGVyb0NWUjpoZXRlcm9SUl9zZSkKCk1ldGFib2xpc20uIDwtIGhldGVyb2cxICU+JQogIGZpbHRlciguLCBHcm91cGluZ1Rlcm0gPT0gIk1ldGFib2xpc20iKSAlPiUKICBzZWxlY3QoLiwgLWRhdGEpICU+JQogIG11dGF0ZSgKICAgIGhldGVyb0NWUiA9IC5bWzJdXVtbMV1dJGIsIGhldGVyb0NWUl9sb3dlciA9IC5bWzJdXVtbMV1dJGNpLmxiLCBoZXRlcm9DVlJfdXBwZXIgPSAuW1syXV1bWzFdXSRjaS51YiwgaGV0ZXJvQ1ZSX3NlID0gLltbMl1dW1sxXV0kc2UsCiAgICBoZXRlcm9WUiA9IC5bWzNdXVtbMV1dJGIsIGhldGVyb1ZSX2xvd2VyID0gLltbM11dW1sxXV0kY2kubGIsIGhldGVyb1ZSX3VwcGVyID0gLltbM11dW1sxXV0kY2kudWIsIGhldGVyb1ZSX3NlID0gLltbM11dW1sxXV0kc2UsCiAgICBoZXRlcm9SUiA9IC5bWzRdXVtbMV1dJGIsIGhldGVyb1JSX2xvd2VyID0gLltbNF1dW1sxXV0kY2kubGIsIGhldGVyb1JSX3VwcGVyID0gLltbNF1dW1sxXV0kY2kudWIsIGhldGVyb1JSX3NlID0gLltbNF1dW1sxXV0kc2UKICApICU+JQogIHNlbGVjdCguLCBHcm91cGluZ1Rlcm0sIGhldGVyb0NWUjpoZXRlcm9SUl9zZSkKCk1vcnBob2xvZ3kuIDwtIGhldGVyb2cxICU+JQogIGZpbHRlciguLCBHcm91cGluZ1Rlcm0gPT0gIk1vcnBob2xvZ3kiKSAlPiUKICBzZWxlY3QoLiwgLWRhdGEpICU+JQogIG11dGF0ZSgKICAgIGhldGVyb0NWUiA9IC5bWzJdXVtbMV1dJGIsIGhldGVyb0NWUl9sb3dlciA9IC5bWzJdXVtbMV1dJGNpLmxiLCBoZXRlcm9DVlJfdXBwZXIgPSAuW1syXV1bWzFdXSRjaS51YiwgaGV0ZXJvQ1ZSX3NlID0gLltbMl1dW1sxXV0kc2UsCiAgICBoZXRlcm9WUiA9IC5bWzNdXVtbMV1dJGIsIGhldGVyb1ZSX2xvd2VyID0gLltbM11dW1sxXV0kY2kubGIsIGhldGVyb1ZSX3VwcGVyID0gLltbM11dW1sxXV0kY2kudWIsIGhldGVyb1ZSX3NlID0gLltbM11dW1sxXV0kc2UsCiAgICBoZXRlcm9SUiA9IC5bWzRdXVtbMV1dJGIsIGhldGVyb1JSX2xvd2VyID0gLltbNF1dW1sxXV0kY2kubGIsIGhldGVyb1JSX3VwcGVyID0gLltbNF1dW1sxXV0kY2kudWIsIGhldGVyb1JSX3NlID0gLltbNF1dW1sxXV0kc2UKICApICU+JQogIHNlbGVjdCguLCBHcm91cGluZ1Rlcm0sIGhldGVyb0NWUjpoZXRlcm9SUl9zZSkKCkhlYXJ0LiA8LSBoZXRlcm9nMSAlPiUKICBmaWx0ZXIoLiwgR3JvdXBpbmdUZXJtID09ICJIZWFydCIpICU+JQogIHNlbGVjdCguLCAtZGF0YSkgJT4lCiAgbXV0YXRlKAogICAgaGV0ZXJvQ1ZSID0gLltbMl1dW1sxXV0kYiwgaGV0ZXJvQ1ZSX2xvd2VyID0gLltbMl1dW1sxXV0kY2kubGIsIGhldGVyb0NWUl91cHBlciA9IC5bWzJdXVtbMV1dJGNpLnViLCBoZXRlcm9DVlJfc2UgPSAuW1syXV1bWzFdXSRzZSwKICAgIGhldGVyb1ZSID0gLltbM11dW1sxXV0kYiwgaGV0ZXJvVlJfbG93ZXIgPSAuW1szXV1bWzFdXSRjaS5sYiwgaGV0ZXJvVlJfdXBwZXIgPSAuW1szXV1bWzFdXSRjaS51YiwgaGV0ZXJvVlJfc2UgPSAuW1szXV1bWzFdXSRzZSwKICAgIGhldGVyb1JSID0gLltbNF1dW1sxXV0kYiwgaGV0ZXJvUlJfbG93ZXIgPSAuW1s0XV1bWzFdXSRjaS5sYiwgaGV0ZXJvUlJfdXBwZXIgPSAuW1s0XV1bWzFdXSRjaS51YiwgaGV0ZXJvUlJfc2UgPSAuW1s0XV1bWzFdXSRzZQogICkgJT4lCiAgc2VsZWN0KC4sIEdyb3VwaW5nVGVybSwgaGV0ZXJvQ1ZSOmhldGVyb1JSX3NlKQoKRXllLiA8LSBoZXRlcm9nMSAlPiUKICBmaWx0ZXIoLiwgR3JvdXBpbmdUZXJtID09ICJFeWUiKSAlPiUKICBzZWxlY3QoLiwgLWRhdGEpICU+JQogIG11dGF0ZSgKICAgIGhldGVyb0NWUiA9IC5bWzJdXVtbMV1dJGIsIGhldGVyb0NWUl9sb3dlciA9IC5bWzJdXVtbMV1dJGNpLmxiLCBoZXRlcm9DVlJfdXBwZXIgPSAuW1syXV1bWzFdXSRjaS51YiwgaGV0ZXJvQ1ZSX3NlID0gLltbMl1dW1sxXV0kc2UsCiAgICBoZXRlcm9WUiA9IC5bWzNdXVtbMV1dJGIsIGhldGVyb1ZSX2xvd2VyID0gLltbM11dW1sxXV0kY2kubGIsIGhldGVyb1ZSX3VwcGVyID0gLltbM11dW1sxXV0kY2kudWIsIGhldGVyb1ZSX3NlID0gLltbM11dW1sxXV0kc2UsCiAgICBoZXRlcm9SUiA9IC5bWzRdXVtbMV1dJGIsIGhldGVyb1JSX2xvd2VyID0gLltbNF1dW1sxXV0kY2kubGIsIGhldGVyb1JSX3VwcGVyID0gLltbNF1dW1sxXV0kY2kudWIsIGhldGVyb1JSX3NlID0gLltbNF1dW1sxXV0kc2UKICApICU+JQogIHNlbGVjdCguLCBHcm91cGluZ1Rlcm0sIGhldGVyb0NWUjpoZXRlcm9SUl9zZSkKCmhldGVyb2cyIDwtIGJpbmRfcm93cyhCZWhhdmlvdXIuLCBNb3JwaG9sb2d5LiwgTWV0YWJvbGlzbS4sIFBoeXNpb2xvZ3kuLCBJbW11bm9sb2d5LiwgSGVtYXRvbG9neS4sIEhlYXJ0LiwgSGVhcmluZy4sIEV5ZS4pCiMgc3RyKGhldGVyb2cyKQpgYGAKCiMjIyMgSGV0ZXJvZ2VuZWl0eSBQTE9UClJlc3RydWN0dXJlIGRhdGEgZm9yIHBsb3R0aW5nIAoKYGBge3J9CmhldGVyb2czIDwtIGdhdGhlcihoZXRlcm9nMiwgcGFyYW1ldGVyLCB2YWx1ZSwgYyhoZXRlcm9DVlIsIGhldGVyb1ZSLCBoZXRlcm9SUiksIGZhY3Rvcl9rZXkgPSBUUlVFKQoKaGV0ZXJvQ1ZSLmNpIDwtIGhldGVyb2czICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImhldGVyb0NWUiIpICU+JQogIG11dGF0ZShjaS5sb3cgPSBoZXRlcm9DVlJfbG93ZXIsIGNpLmhpZ2ggPSBoZXRlcm9DVlJfdXBwZXIpCmhldGVyb1ZSLmNpIDwtIGhldGVyb2czICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImhldGVyb1ZSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGhldGVyb1ZSX2xvd2VyLCBjaS5oaWdoID0gaGV0ZXJvVlJfdXBwZXIpCmhldGVyb1JSLmNpIDwtIGhldGVyb2czICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImhldGVyb1JSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGhldGVyb1JSX2xvd2VyLCBjaS5oaWdoID0gaGV0ZXJvUlJfdXBwZXIpCgpoZXRlcm9nNCA8LSBiaW5kX3Jvd3MoaGV0ZXJvQ1ZSLmNpLCBoZXRlcm9WUi5jaSwgaGV0ZXJvUlIuY2kpICU+JSBzZWxlY3QoR3JvdXBpbmdUZXJtLCBwYXJhbWV0ZXIsIHZhbHVlLCBjaS5sb3csIGNpLmhpZ2gpCgojICoqUmUtb3JkZXIgZ3JvdXBpbmcgdGVybXMKCmhldGVyb2c0JEdyb3VwaW5nVGVybSA8LSBmYWN0b3IoaGV0ZXJvZzQkR3JvdXBpbmdUZXJtLCBsZXZlbHMgPSBjKCJCZWhhdmlvdXIiLCAiTW9ycGhvbG9neSIsICJNZXRhYm9saXNtIiwgIlBoeXNpb2xvZ3kiLCAiSW1tdW5vbG9neSIsICJIZW1hdG9sb2d5IiwgIkhlYXJ0IiwgIkhlYXJpbmciLCAiRXllIikpCmhldGVyb2c0JEdyb3VwaW5nVGVybSA8LSBmYWN0b3IoaGV0ZXJvZzQkR3JvdXBpbmdUZXJtLCByZXYobGV2ZWxzKGhldGVyb2c0JEdyb3VwaW5nVGVybSkpKQpoZXRlcm9nNCRsYWJlbCA8LSAiQWxsIHRyYWl0cyIKIyB3cml0ZS5jc3YoaGV0ZXJvZzQsICJoZXRlcm9nNC5jc3YiKQpgYGAKCiMjIyBQbG90IEZJR1VSRSA0IC0gQyhTZWNvbmQtb3JkZXIgbWV0YSBhbmFseXNpcyBvbiBoZXRlcm9nZW5laXR5KQoKUGxvdCBGaWc0IGFsbCB0cmFpdHMKCmBgYHtyfQpoZXRlcm9nNSA8LSBoZXRlcm9nNApoZXRlcm9nNSRtZWFuIDwtIGFzLm51bWVyaWMoZXhwKGhldGVyb2c1JHZhbHVlKSkKaGV0ZXJvZzUkY2kubCA8LSBhcy5udW1lcmljKGV4cChoZXRlcm9nNSRjaS5sb3cpKQpoZXRlcm9nNSRjaS5oIDwtIGFzLm51bWVyaWMoZXhwKGhldGVyb2c1JGNpLmhpZ2gpKQoKaGV0ZXJvZzYgPC0gaGV0ZXJvZzUKCkhldGVybzRjIDwtCiAgaGV0ZXJvZzYgJT4lCiAgZmlsdGVyKAogICAgcGFyYW1ldGVyID09ICJoZXRlcm9DVlIiIHwgcGFyYW1ldGVyID09ICJoZXRlcm9SUiIKICApICU+JQogIGdncGxvdChhZXMoeSA9IEdyb3VwaW5nVGVybSwgeCA9IG1lYW4pKSArCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKAogICAgeG1pbiA9IGNpLmwsCiAgICB4bWF4ID0gY2kuaAogICksCiAgaGVpZ2h0ID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBwYXJhbWV0ZXIpLAogICAgZmlsbCA9ICJibGFjayIsCiAgICBjb2xvciA9ICJibGFjayIsIHNpemUgPSAyLjIsCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbGltaXRzID0gYygtMC4xLCAxLjQpLAogICAgIyBicmVha3MgPSBjKDAsIDAuMSwgMC4yKSwKICAgIG5hbWUgPSAic2lnbWFeMiIKICApICsKICAjIGdlb21fdmxpbmUoeGludGVyY2VwdD0wLAogICMgY29sb3I9J2JsYWNrJywKICAjIGxpbmV0eXBlPSdkYXNoZWQnKSsKICBmYWNldF9ncmlkKAogICAgY29scyA9IHZhcnMocGFyYW1ldGVyKSwgcm93cyA9IHZhcnMobGFiZWwpLAogICAgbGFiZWxsZXIgPSBsYWJlbF93cmFwX2dlbih3aWR0aCA9IDIzKSwKICAgIHNjYWxlcyA9ICJmcmVlIiwKICAgIHNwYWNlID0gImZyZWUiCiAgKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNzAsIHNpemUgPSAxMCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxNSwgciA9IDE1LCBiID0gMTUsIGwgPSAxNSkpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9IE5VTEwsIGxpbmV0eXBlID0gImJsYW5rIiwgZmlsbCA9ICJncmF5OTAiKSwKICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG91ciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG9yID0gImdyYXk5NSIpLAogICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTQpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKIyBIZXRlcm80YwoKIyBnZ3NhdmUoIkZpZzQucGRmIiwgcGxvdCA9IE1ldGFtZXRhX0ZpZzRfYWxsdHJhaXRzLCB3aWR0aCA9IDcsIGhlaWdodCA9IDYpCmBgYAoKIyMjIyBDb21iaW5lZCBGaWd1cmUgNDogb3ZlcmFsbCAoQ291bnQgZGF0YSwgTWV0YSBhbmx5c2lzIHJlc3VsdHMsIEhldGVyb2dlbmVpdHkpCgpgYGB7cn0KCkZpZzQgPC0gZ2dhcnJhbmdlKG1hbGViaWFzX0ZpZzJfYWxsdHJhaXRzLCBNZXRhbWV0YV9GaWczX2FsbHRyYWl0cywgSGV0ZXJvNGMsIG5yb3cgPSAzLCBhbGlnbiA9ICJ2IiwgaGVpZ2h0cyA9IGMoMSwgMSwgMSksIGxhYmVscyA9IGMoIkEiLCAiQiIsICJDIikpCkZpZzQKIyBnZ3NhdmUoIkZpZzRfT3ZlcmFsbFJlc3VsdHMucGRmIiwgcGxvdCA9IEZpZzQsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNSkKYGBgCgojIyBTdXBwbGVtZW50YWwgRmlndXJlcwoKYGBge3J9CiMjIEhldGVyb2duZWl0eSwgUzEgQwoKSGV0ZXJvUzEgPC0gaGV0ZXJvZzUgJT4lCiAgZ2dwbG90KGFlcyh5ID0gR3JvdXBpbmdUZXJtLCB4ID0gbWVhbikpICsKICBnZW9tX2Vycm9yYmFyaChhZXMoCiAgICB4bWluID0gY2kubCwKICAgIHhtYXggPSBjaS5oCiAgKSwKICBoZWlnaHQgPSAwLjEsIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHBhcmFtZXRlciksCiAgICBmaWxsID0gImJsYWNrIiwKICAgIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDIuMiwKICAgIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBsaW1pdHMgPSBjKC0wLjEsIDEuNCksCiAgICAjIGJyZWFrcyA9IGMoMCwgMC4xLCAwLjIpLAogICAgbmFtZSA9ICJFZmZlY3Qgc2l6ZSIKICApICsKICAjIGdlb21fdmxpbmUoeGludGVyY2VwdD0wLAogICMgY29sb3I9J2JsYWNrJywKICAjIGxpbmV0eXBlPSdkYXNoZWQnKSsKICBmYWNldF9ncmlkKAogICAgY29scyA9IHZhcnMocGFyYW1ldGVyKSwgcm93cyA9IHZhcnMobGFiZWwpLAogICAgbGFiZWxsZXIgPSBsYWJlbF93cmFwX2dlbih3aWR0aCA9IDIzKSwKICAgIHNjYWxlcyA9ICJmcmVlIiwKICAgIHNwYWNlID0gImZyZWUiCiAgKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNzAsIHNpemUgPSAxMCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxNSwgciA9IDE1LCBiID0gMTUsIGwgPSAxNSkpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9IE5VTEwsIGxpbmV0eXBlID0gImJsYW5rIiwgZmlsbCA9ICJncmF5OTAiKSwKICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG91ciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG9yID0gImdyYXk5NSIpLAogICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKIyBIZXRlcm9TMQoKIyBnZ3NhdmUoIkZpZzQucGRmIiwgcGxvdCA9IE1ldGFtZXRhX0ZpZzRfYWxsdHJhaXRzLCB3aWR0aCA9IDcsIGhlaWdodCA9IDYpCmBgYAoKIyMgQ291bnQgZGF0YSwgaW5jbHVkaW5nIGxuVlIgKEZpZyBTMSBBKQoKYGBge3J9CiMgKlByZXBhcmUgZGF0YSBmb3IgYWxsIHRyYWl0cwoKbWV0YS5wbG90Mi5hbGwgPC0gbWV0YV9jbGVhbiAlPiUKICBzZWxlY3QobG5DVlIsIGxuVlIsIGxuUlIsIEdyb3VwaW5nVGVybSkgJT4lCiAgYXJyYW5nZShHcm91cGluZ1Rlcm0pCgptZXRhLnBsb3QyLmFsbC5iUzEgPC0gZ2F0aGVyKG1ldGEucGxvdDIuYWxsLCB0cmFpdCwgdmFsdWUsIGMobG5DVlIsIGxuVlIsIGxuUlIpKQoKbWV0YS5wbG90Mi5hbGwuYlMxJHRyYWl0IDwtIGZhY3RvcihtZXRhLnBsb3QyLmFsbC5iUzEkdHJhaXQsIGxldmVscyA9IGMoImxuQ1ZSIiwgImxuVlIiLCAibG5SUiIpKQoKbWV0YS5wbG90Mi5hbGwuY1MxIDwtIG1ldGEucGxvdDIuYWxsLmJTMSAlPiUKICBncm91cF9ieV9hdCh2YXJzKHRyYWl0LCBHcm91cGluZ1Rlcm0pKSAlPiUKICBzdW1tYXJpc2UoCiAgICBtYWxlYmlhcyA9IHN1bSh2YWx1ZSA+IDApLCBmZW1hbGViaWFzID0gc3VtKHZhbHVlIDw9IDApLCB0b3RhbCA9IG1hbGViaWFzICsgZmVtYWxlYmlhcywKICAgIG1hbGVwZXJjZW50ID0gbWFsZWJpYXMgKiAxMDAgLyB0b3RhbCwgZmVtYWxlcGVyY2VudCA9IGZlbWFsZWJpYXMgKiAxMDAgLyB0b3RhbAogICkKCm1ldGEucGxvdDIuYWxsLmNTMSRsYWJlbCA8LSAiQWxsIHRyYWl0cyIKCiMgcmVzdHJ1Y3R1cmUgdG8gY3JlYXRlIHN0YWNrZWQgYmFyIHBsb3RzCgptZXRhLnBsb3QyLmFsbC5kUzEgPC0gYXMuZGF0YS5mcmFtZShtZXRhLnBsb3QyLmFsbC5jUzEpCm1ldGEucGxvdDIuYWxsLmVTMSA8LSBnYXRoZXIobWV0YS5wbG90Mi5hbGwuZFMxLCBrZXkgPSBzZXgsIHZhbHVlID0gcGVyY2VudCwgbWFsZXBlcmNlbnQ6ZmVtYWxlcGVyY2VudCwgZmFjdG9yX2tleSA9IFRSVUUpCgojIGNyZWF0ZSBuZXcgc2FtcGxlIHNpemUgdmFyaWFibGUKCm1ldGEucGxvdDIuYWxsLmVTMSRzYW1wbGVzaXplIDwtIHdpdGgobWV0YS5wbG90Mi5hbGwuZVMxLCBpZmVsc2Uoc2V4ID09ICJtYWxlcGVyY2VudCIsIG1hbGViaWFzLCBmZW1hbGViaWFzKSkKCm1hbGViaWFzX0ZpZ1MxX2FsbHRyYWl0cyA8LQogIGdncGxvdChtZXRhLnBsb3QyLmFsbC5lUzEpICsKICBhZXMoeCA9IEdyb3VwaW5nVGVybSwgeSA9IHBlcmNlbnQsIGZpbGwgPSBzZXgpICsKICBnZW9tX2NvbCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1MCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JheTQwIikgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSBzdWJzZXQobWV0YS5wbG90Mi5hbGwuZVMxLCBzYW1wbGVzaXplICE9IDApLCBhZXMobGFiZWwgPSBzYW1wbGVzaXplKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IC41KSwKICAgIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDMuNQogICkgKwogIGZhY2V0X2dyaWQoCiAgICBjb2xzID0gdmFycyh0cmFpdCksIHJvd3MgPSB2YXJzKGxhYmVsKSwgbGFiZWxsZXIgPSBsYWJlbF93cmFwX2dlbih3aWR0aCA9IDE4KSwKICAgIHNjYWxlcyA9ICJmcmVlIiwgc3BhY2UgPSAiZnJlZSIKICApICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsKICB0aGVtZSgKICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDI3MCwgc2l6ZSA9IDEwLCBtYXJnaW4gPSBtYXJnaW4odCA9IDE1LCByID0gMTUsIGIgPSAxNSwgbCA9IDE1KSksCiAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gTlVMTCwgbGluZXR5cGUgPSAiYmxhbmsiLCBmaWxsID0gImdyYXk5MCIpLAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC41LCAibGluZXMiKSwKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9saW5lKGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3VyID0gImdyYXk5NSIpLAogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3IgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkKICApICsKICBjb29yZF9mbGlwKCkKCiMgbWFsZWJpYXNfRmlnUzFfYWxsdHJhaXRzICAgICAjKHBhbmVsIEEgaW4gRmlndXJlIFMxKQpgYGAKCiMjIyAgT3ZlcmFsbCByZXN1bHRzIG9mIHNlY29uZCBvcmRlciBtZXRhIGFuYWx5c2lzIChGaWd1cmUgNDogb3ZlcmFsbCwgRmlndXJlIDU6IHNleC1iaWFzKSwgSU5DTFVESU5HIFZSCiMjIyMgUmVzdHJ1Y3R1cmUgZGF0YSBmb3IgcGxvdHRpbmcgClJlc3RydWN0dXJlIE1BTEUgZGF0YSBmb3IgcGxvdHRpbmcgCgpgYGB7cn0Kb3ZlcmFsbDMubWFsZS5zaWdTIDwtIGdhdGhlcihvdmVyYWxsLm1hbGUucGxvdDMsIHBhcmFtZXRlciwgdmFsdWUsIGMobG5DVlIsIGxuVlIsIGxuUlIpLCBmYWN0b3Jfa2V5ID0gVFJVRSkKCmxuQ1ZSLmNpIDwtIG92ZXJhbGwzLm1hbGUuc2lnUyAlPiUKICBmaWx0ZXIocGFyYW1ldGVyID09ICJsbkNWUiIpICU+JQogIG11dGF0ZShjaS5sb3cgPSBsbkNWUl9sb3dlciwgY2kuaGlnaCA9IGxuQ1ZSX3VwcGVyKQpsblZSLmNpIDwtIG92ZXJhbGwzLm1hbGUuc2lnUyAlPiUKICBmaWx0ZXIocGFyYW1ldGVyID09ICJsblZSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuVlJfbG93ZXIsIGNpLmhpZ2ggPSBsblZSX3VwcGVyKQpsblJSLmNpIDwtIG92ZXJhbGwzLm1hbGUuc2lnUyAlPiUKICBmaWx0ZXIocGFyYW1ldGVyID09ICJsblJSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuUlJfbG93ZXIsIGNpLmhpZ2ggPSBsblJSX3VwcGVyKQoKb3ZlcmFsbDQubWFsZS5zaWdTIDwtIGJpbmRfcm93cyhsbkNWUi5jaSwgbG5WUi5jaSwgbG5SUi5jaSkgJT4lIHNlbGVjdChHcm91cGluZ1Rlcm0sIHBhcmFtZXRlciwgdmFsdWUsIGNpLmxvdywgY2kuaGlnaCkKCm92ZXJhbGw0Lm1hbGUuc2lnUyRsYWJlbCA8LSAiQ0kgbm90IG92ZXJsYXBwaW5nIHplcm8iCmBgYAoKRGF0YSBhcmUgcmVzdHJ1Y3R1cmVkLCBhbmQgZ3JvdXBpbmcgdGVybXMgYXJlIGJlaW5nIHJlLW9yZGVyZWQKCmBgYHtyfQpvdmVyYWxsM1MgPC0gZ2F0aGVyKG92ZXJhbGwyLCBwYXJhbWV0ZXIsIHZhbHVlLCBjKGxuQ1ZSLCBsblZSLCBsblJSKSwgZmFjdG9yX2tleSA9IFRSVUUpCgpsbkNWUi5jaSA8LSBvdmVyYWxsM1MgJT4lCiAgZmlsdGVyKHBhcmFtZXRlciA9PSAibG5DVlIiKSAlPiUKICBtdXRhdGUoY2kubG93ID0gbG5DVlJfbG93ZXIsIGNpLmhpZ2ggPSBsbkNWUl91cHBlcikKbG5WUi5jaSA8LSBvdmVyYWxsM1MgJT4lCiAgZmlsdGVyKHBhcmFtZXRlciA9PSAibG5WUiIpICU+JQogIG11dGF0ZShjaS5sb3cgPSBsblZSX2xvd2VyLCBjaS5oaWdoID0gbG5WUl91cHBlcikKbG5SUi5jaSA8LSBvdmVyYWxsM1MgJT4lCiAgZmlsdGVyKHBhcmFtZXRlciA9PSAibG5SUiIpICU+JQogIG11dGF0ZShjaS5sb3cgPSBsblJSX2xvd2VyLCBjaS5oaWdoID0gbG5SUl91cHBlcikKCm92ZXJhbGw0UyA8LSBiaW5kX3Jvd3MobG5DVlIuY2ksIGxuVlIuY2ksIGxuUlIuY2kpICU+JSBzZWxlY3QoR3JvdXBpbmdUZXJtLCBwYXJhbWV0ZXIsIHZhbHVlLCBjaS5sb3csIGNpLmhpZ2gpCgojIHJlLW9yZGVyIEdyb3VwaW5nIFRlcm1zCgpvdmVyYWxsNFMkR3JvdXBpbmdUZXJtIDwtIGZhY3RvcihvdmVyYWxsNFMkR3JvdXBpbmdUZXJtLCBsZXZlbHMgPSBjKCJCZWhhdmlvdXIiLCAiTW9ycGhvbG9neSIsICJNZXRhYm9saXNtIiwgIlBoeXNpb2xvZ3kiLCAiSW1tdW5vbG9neSIsICJIZW1hdG9sb2d5IiwgIkhlYXJ0IiwgIkhlYXJpbmciLCAiRXllIiwgIkFsbCIpKQpvdmVyYWxsNFMkR3JvdXBpbmdUZXJtIDwtIGZhY3RvcihvdmVyYWxsNFMkR3JvdXBpbmdUZXJtLCByZXYobGV2ZWxzKG92ZXJhbGw0UyRHcm91cGluZ1Rlcm0pKSkKb3ZlcmFsbDRTJGxhYmVsIDwtICJBbGwgdHJhaXRzIgpgYGAKCiMjIyMgUHJlcGFyYXRpb24gZm9yIFBsb3RzIEZJR1VSRSBTMUIgJiBTMkIsIFMyRCAoU2Vjb25kLW9yZGVyIG1ldGEgYW5hbHlzaXMgcmVzdWx0cywgSU5DTCBsblZSKQpQcmVwYXJhdGlvbjogU3ViLVBsb3QgIGZvciBGaWd1cmUgUzE6IGFsbCB0cmFpdHMgKFMxIEIpCgpgYGB7cn0KTWV0YW1ldGFfRmlnUzFfYWxsdHJhaXRzIDwtIG92ZXJhbGw0UyAlPiUKCiAgZ2dwbG90KGFlcyh5ID0gR3JvdXBpbmdUZXJtLCB4ID0gdmFsdWUpKSArCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKAogICAgeG1pbiA9IGNpLmxvdywKICAgIHhtYXggPSBjaS5oaWdoCiAgKSwKICBoZWlnaHQgPSAwLjEsIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHBhcmFtZXRlciksCiAgICBmaWxsID0gImJsYWNrIiwKICAgIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDIuMiwKICAgIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBsaW1pdHMgPSBjKC0wLjI0LCAwLjI1KSwKICAgIGJyZWFrcyA9IGMoLTAuMiwgLTAuMSwgMCwgMC4xLCAwLjIpLAogICAgbmFtZSA9ICJFZmZlY3Qgc2l6ZSIKICApICsKICBnZW9tX3ZsaW5lKAogICAgeGludGVyY2VwdCA9IDAsCiAgICBjb2xvciA9ICJibGFjayIsCiAgICBsaW5ldHlwZSA9ICJkYXNoZWQiCiAgKSArCiAgZmFjZXRfZ3JpZCgKICAgIGNvbHMgPSB2YXJzKHBhcmFtZXRlciksIHJvd3MgPSB2YXJzKGxhYmVsKSwKICAgIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSAyMyksCiAgICBzY2FsZXMgPSAiZnJlZSIsCiAgICBzcGFjZSA9ICJmcmVlIgogICkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjcwLCBzaXplID0gMTAsIG1hcmdpbiA9IG1hcmdpbih0ID0gMTUsIHIgPSAxNSwgYiA9IDE1LCBsID0gMTUpKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOVUxMLCBsaW5ldHlwZSA9ICJibGFuayIsIGZpbGwgPSAiZ3JheTkwIiksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE0KSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgTWV0YW1ldGFfRmlnUzFfYWxsdHJhaXRzCmBgYAoKIyMjIyBDb21iaW5lZCBGaWd1cmUgUzE6IG92ZXJhbGwgQ291bnQgZGF0YSwgTWV0YSBhbmx5c2lzIHJlc3VsdHMsIEhldGVyb2dlbmVpdHkpCgpgYGB7cn0KRmlnUzEgPC0gZ2dhcnJhbmdlKG1hbGViaWFzX0ZpZ1MxX2FsbHRyYWl0cyArIHhsYWIoInBlcmNlbnRhZ2Ugc2V4IGJpYXMiKSwgTWV0YW1ldGFfRmlnUzFfYWxsdHJhaXRzLCBIZXRlcm9TMSwgbnJvdyA9IDMsIGFsaWduID0gInYiLCBoZWlnaHRzID0gYygxLCAxLCAxKSwgbGFiZWxzID0gYygiQSIsICJCIiwgIkMiKSkKRmlnUzEKIyBnZ3NhdmUoIkZpZ1MxX092ZXJhbGxSZXN1bHRzLnBkZiIsIHBsb3QgPSBGaWc0LCB3aWR0aCA9IDYsIGhlaWdodCA9IDUpCmBgYAoKIyMgRmlndXJlIFMyOiBzZXgtYmlhcywgaW5jbHVkaW5nIFZSCgpQbG90IEZpZ1MyIGFsbCBzaWduaWZpY2FudCByZXN1bHRzIChDSSBub3Qgb3ZlcmxhcHBpbmcgemVybykgZm9yIG1hbGVzCgpgYGB7cn0KbWV0YS5wbG90Mi5zaWcuYlMgPC0gbWV0YS5wbG90Mi5zaWdbLCBjKCJsbkNWUiIsICJsblZSIiwgImxuUlIiLCAibG5DVlJzaWciLCAibG5WUnNpZyIsICJsblJSc2lnIiwgIkdyb3VwaW5nVGVybSIpXQoKbWV0YS5wbG90Mi5zaWcuY1MgPC0gZ2F0aGVyKG1ldGEucGxvdDIuc2lnLmJTLCB0cmFpdCwgdmFsdWUsIGxuQ1ZSOmxuUlIpCm1ldGEucGxvdDIuc2lnLmNTJHNpZyA8LSAicGxhY2Vob2xkZXIiCgptZXRhLnBsb3QyLnNpZy5jUyR0cmFpdCA8LSBmYWN0b3IobWV0YS5wbG90Mi5zaWcuY1MkdHJhaXQsIGxldmVscyA9IGMoImxuQ1ZSIiwgImxuVlIiLCAibG5SUiIpKQoKbWV0YS5wbG90Mi5zaWcuY1Mkc2lnIDwtIGlmZWxzZShtZXRhLnBsb3QyLnNpZy5jUyR0cmFpdCA9PSAibG5DVlIiLCBtZXRhLnBsb3QyLnNpZy5jUyRsbkNWUnNpZywKICBpZmVsc2UobWV0YS5wbG90Mi5zaWcuY1MkdHJhaXQgPT0gImxuVlIiLCBtZXRhLnBsb3QyLnNpZy5jUyRsblZSc2lnLCBtZXRhLnBsb3QyLnNpZy5jUyRsblJSc2lnKQopCgojIGNob29zaW5nIHNleCBiaWFzZWQgbG4tcmF0aW9zIHNpZ25pZmljYW50bHkgbGFyZ2VyIHRoYW4gMAptZXRhLnBsb3RTMi5zaWcubWFsZWJpYXMgPC0gbWV0YS5wbG90Mi5zaWcuY1MgJT4lCiAgZ3JvdXBfYnlfYXQodmFycyh0cmFpdCwgR3JvdXBpbmdUZXJtKSkgJT4lCiAgZmlsdGVyKHNpZyA9PSAxKSAlPiUKICBzdW1tYXJpc2UobWFsZV9zaWcgPSBzdW0odmFsdWUgPiAwKSwgZmVtYWxlX3NpZyA9IHN1bSh2YWx1ZSA8IDApLCB0b3RhbCA9IG1hbGVfc2lnICsgZmVtYWxlX3NpZykKCm1ldGEucGxvdFMyLnNpZy5tYWxlYmlhcyA8LSB1bmdyb3VwKG1ldGEucGxvdFMyLnNpZy5tYWxlYmlhcykgJT4lCiAgYWRkX3Jvdyh0cmFpdCA9ICJsbkNWUiIsIEdyb3VwaW5nVGVybSA9ICJIZWFyaW5nIiwgbWFsZV9zaWcgPSAwLCBmZW1hbGVfc2lnID0gMCwgLmJlZm9yZSA9IDQpICU+JSAjIGFkZCAiSGVhcmluZyIgZm9yIGxuQ1ZSIChub3QgZmlsdGVyZWQgYXMgb25seSB6ZXJvcykKICBtdXRhdGUobWFsZXBlcmNlbnQgPSBtYWxlX3NpZyAqIDEwMCAvIHRvdGFsLCBmZW1hbGVwZXJjZW50ID0gZmVtYWxlX3NpZyAqIDEwMCAvIHRvdGFsKQoKbWV0YS5wbG90UzIuc2lnLm1hbGViaWFzJGxhYmVsIDwtICJDSSBub3Qgb3ZlcmxhcHBpbmcgemVybyIKCiMgcmVzdHJ1Y3R1cmUgdG8gY3JlYXRlIHN0YWNrZWQgYmFyIHBsb3RzCgptZXRhLnBsb3RTMi5zaWcuYm90aHNleGVzIDwtIGFzLmRhdGEuZnJhbWUobWV0YS5wbG90UzIuc2lnLm1hbGViaWFzKQptZXRhLnBsb3RTMi5zaWcuYm90aHNleGVzLmIgPC0gZ2F0aGVyKG1ldGEucGxvdFMyLnNpZy5ib3Roc2V4ZXMsIGtleSA9IHNleCwgdmFsdWUgPSBwZXJjZW50LCBtYWxlcGVyY2VudDpmZW1hbGVwZXJjZW50LCBmYWN0b3Jfa2V5ID0gVFJVRSkKCiMgY3JlYXRlIG5ldyBzYW1wbGUgc2l6ZSB2YXJpYWJsZQoKbWV0YS5wbG90UzIuc2lnLmJvdGhzZXhlcy5iJHNhbXBsZXNpemUgPC0gd2l0aChtZXRhLnBsb3RTMi5zaWcuYm90aHNleGVzLmIsIGlmZWxzZShzZXggPT0gIm1hbGVwZXJjZW50IiwgbWFsZV9zaWcsIGZlbWFsZV9zaWcpKQoKIyAqUGxvdCBGaWcyIGFsbCBzaWduaWZpY2FudCByZXN1bHRzIChDSSBub3Qgb3ZlcmxhcHBpbmcgemVybyk6CiMgICAgIG5vIHNpZy4gbG5DVlIgZm9yICdIZWFyaW5nJyBpbiBlaXRoZXIgc2V4OyBubyBzaWcuIG1hbGUtYmlhc2VkIGxuQ1ZSIGZvciAnSW1tdW5vbG9neScgYW5kICdFeWUsIGFuZCBubyBzaWcuIG1hbGUtYmlhc2VkIGxuVlIgZm9yICdFeWUnCgoKbWFsZWJpYXNfRmlnUzJfc2lndHJhaXRzIDwtCiAgZ2dwbG90KG1ldGEucGxvdFMyLnNpZy5ib3Roc2V4ZXMuYikgKwogIGFlcyh4ID0gR3JvdXBpbmdUZXJtLCB5ID0gcGVyY2VudCwgZmlsbCA9IHNleCkgKwogIGdlb21fY29sKCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDUwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJncmF5NDAiKSArCiAgZ2VvbV90ZXh0KAogICAgZGF0YSA9IHN1YnNldChtZXRhLnBsb3RTMi5zaWcuYm90aHNleGVzLmIsIHNhbXBsZXNpemUgIT0gMCksIGFlcyhsYWJlbCA9IHNhbXBsZXNpemUpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gLjUpLAogICAgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMy41CiAgKSArCiAgZmFjZXRfZ3JpZCgKICAgIGNvbHMgPSB2YXJzKHRyYWl0KSwgcm93cyA9IHZhcnMobGFiZWwpLCBsYWJlbGxlciA9IGxhYmVsX3dyYXBfZ2VuKHdpZHRoID0gMTgpLAogICAgc2NhbGVzID0gImZyZWUiLCBzcGFjZSA9ICJmcmVlIgogICkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxOCkgKwogIHRoZW1lKAogICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjcwLCBzaXplID0gMTAsIG1hcmdpbiA9IG1hcmdpbih0ID0gMTUsIHIgPSAxNSwgYiA9IDE1LCBsID0gMTUpKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOVUxMLCBsaW5ldHlwZSA9ICJibGFuayIsIGZpbGwgPSAiZ3JheTkwIiksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICkgKwogIGNvb3JkX2ZsaXAoKQoKIyBtYWxlYmlhc19GaWdTMl9zaWd0cmFpdHMgIyB0aGlzIGlzIEZpZ3VyZSBTMiBBCmBgYAoKUHJlcGFyZSBkYXRhIGZvciB0cmFpdHMgd2l0aCBlZmZlY3Qgc2l6ZSByYXRpb3MgPiAxMCUgbGFyZ2VyIGluIG1hbGVzCgpgYGB7cn0KbWV0YS5wbG90UzIub3ZlcjEwIDwtIG1ldGFfY2xlYW4gJT4lCiAgc2VsZWN0KGxuQ1ZSLCBsblZSLCBsblJSLCBHcm91cGluZ1Rlcm0pICU+JQogIGFycmFuZ2UoR3JvdXBpbmdUZXJtKQoKbWV0YS5wbG90UzIub3ZlcjEwLmIgPC0gZ2F0aGVyKG1ldGEucGxvdFMyLm92ZXIxMCwgdHJhaXQsIHZhbHVlLCBjKGxuQ1ZSLCBsblZSLCBsblJSKSkKCm1ldGEucGxvdFMyLm92ZXIxMC5iJHRyYWl0IDwtIGZhY3RvcihtZXRhLnBsb3RTMi5vdmVyMTAuYiR0cmFpdCwgbGV2ZWxzID0gYygibG5DVlIiLCAibG5WUiIsICJsblJSIikpCgptZXRhLnBsb3RTMi5vdmVyMTAuYyA8LSBtZXRhLnBsb3RTMi5vdmVyMTAuYiAlPiUKICBncm91cF9ieV9hdCh2YXJzKHRyYWl0LCBHcm91cGluZ1Rlcm0pKSAlPiUKICBzdW1tYXJpc2UoCiAgICBtYWxlYmlhcyA9IHN1bSh2YWx1ZSA+IGxvZygxMSAvIDEwKSksIGZlbWFsZWJpYXMgPSBzdW0odmFsdWUgPCBsb2coOSAvIDEwKSksIHRvdGFsID0gbWFsZWJpYXMgKyBmZW1hbGViaWFzLAogICAgbWFsZXBlcmNlbnQgPSBtYWxlYmlhcyAqIDEwMCAvIHRvdGFsLCBmZW1hbGVwZXJjZW50ID0gZmVtYWxlYmlhcyAqIDEwMCAvIHRvdGFsCiAgKQoKbWV0YS5wbG90UzIub3ZlcjEwLmMkbGFiZWwgPC0gIlNleCBkaWZmZXJlbmNlIGluIG0vZiByYXRpb3MgPiAxMCUiCgojIHJlc3RydWN0dXJlIHRvIGNyZWF0ZSBzdGFja2VkIGJhciBwbG90cwoKbWV0YS5wbG90UzIub3ZlcjEwLmMgPC0gYXMuZGF0YS5mcmFtZShtZXRhLnBsb3RTMi5vdmVyMTAuYykKbWV0YS5wbG90UzIub3ZlcjEwLmQgPC0gZ2F0aGVyKG1ldGEucGxvdFMyLm92ZXIxMC5jLCBrZXkgPSBzZXgsIHZhbHVlID0gcGVyY2VudCwgbWFsZXBlcmNlbnQ6ZmVtYWxlcGVyY2VudCwgZmFjdG9yX2tleSA9IFRSVUUpCgojIGNyZWF0ZSBuZXcgc2FtcGxlIHNpemUgdmFyaWFibGUKCm1ldGEucGxvdFMyLm92ZXIxMC5kJHNhbXBsZXNpemUgPC0gd2l0aChtZXRhLnBsb3RTMi5vdmVyMTAuZCwgaWZlbHNlKHNleCA9PSAibWFsZXBlcmNlbnQiLCBtYWxlYmlhcywgZmVtYWxlYmlhcykpCgojICpQbG90IEZpZ1MyIFNleCBkaWZmZXJlbmNlIGluIG0vZiByYXRpbyA+IDEwJQptYWxlYmlhc19GaWdTMl9vdmVyMTAgPC0KICBnZ3Bsb3QobWV0YS5wbG90UzIub3ZlcjEwLmQpICsKICBhZXMoeCA9IEdyb3VwaW5nVGVybSwgeSA9IHBlcmNlbnQsIGZpbGwgPSBzZXgpICsKICBnZW9tX2NvbCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1MCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JheTQwIikgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSBzdWJzZXQobWV0YS5wbG90Mi5vdmVyMTAuZCwgc2FtcGxlc2l6ZSAhPSAwKSwgYWVzKGxhYmVsID0gc2FtcGxlc2l6ZSksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAuNSksCiAgICBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzLjUKICApICsKICBmYWNldF9ncmlkKAogICAgY29scyA9IHZhcnModHJhaXQpLCByb3dzID0gdmFycyhsYWJlbCksIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSAxOCksCiAgICBzY2FsZXMgPSAiZnJlZSIsIHNwYWNlID0gImZyZWUiCiAgKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNzAsIHNpemUgPSAxMCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxNSwgciA9IDE1LCBiID0gMTUsIGwgPSAxNSkpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOVUxMLCBsaW5ldHlwZSA9ICJibGFuayIsIGZpbGwgPSAiZ3JheTkwIiksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICkgKwogIGNvb3JkX2ZsaXAoKQoKIyBtYWxlYmlhc19GaWdTMl9vdmVyMTAgICMoUGFuZWwgQiBpbiBGaWcgUzIgaW4gbXMpCmBgYAoKIyMjIyBGZW1hbGUgRmlndXJlLCBzaWduaWZpY2FudCB0cmFpdHMKRmVtYWxlIEZpZ1MyIEIgc2lnCgpQcmVwYXJlIGRhdGEgZm9yIHRyYWl0cyB3aXRoIENJIG5vdCBvdmVybGFwcGluZyAwCmNyZWF0ZSBjb2x1bW4gd2l0aCAxPSBkaWZmZXJlbnQgZnJvbSB6ZXJvLCAwPSB6ZXJvIGluY2x1ZGVkIGluIENJCgoKUmVzdHJ1Y3R1cmUgZGF0YSBmb3IgcGxvdHRpbmcKCmBgYHtyfQpvdmVyYWxsMy5mZW1hbGUuc2lnUyA8LSBnYXRoZXIob3ZlcmFsbC5mZW1hbGUucGxvdDMsIHBhcmFtZXRlciwgdmFsdWUsIGMobG5DVlIsIGxuVlIsIGxuUlIpLCBmYWN0b3Jfa2V5ID0gVFJVRSkKCmxuQ1ZSLmNpIDwtIG92ZXJhbGwzLmZlbWFsZS5zaWdTICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImxuQ1ZSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuQ1ZSX2xvd2VyLCBjaS5oaWdoID0gbG5DVlJfdXBwZXIpCmxuVlIuY2kgPC0gb3ZlcmFsbDMuZmVtYWxlLnNpZ1MgJT4lCiAgZmlsdGVyKHBhcmFtZXRlciA9PSAibG5WUiIpICU+JQogIG11dGF0ZShjaS5sb3cgPSBsblZSX2xvd2VyLCBjaS5oaWdoID0gbG5WUl91cHBlcikKbG5SUi5jaSA8LSBvdmVyYWxsMy5mZW1hbGUuc2lnUyAlPiUKICBmaWx0ZXIocGFyYW1ldGVyID09ICJsblJSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuUlJfbG93ZXIsIGNpLmhpZ2ggPSBsblJSX3VwcGVyKQoKb3ZlcmFsbDQuZmVtYWxlLnNpZ1MgPC0gYmluZF9yb3dzKGxuQ1ZSLmNpLCBsblZSLmNpLCBsblJSLmNpKSAlPiUgc2VsZWN0KEdyb3VwaW5nVGVybSwgcGFyYW1ldGVyLCB2YWx1ZSwgY2kubG93LCBjaS5oaWdoKQoKb3ZlcmFsbDQuZmVtYWxlLnNpZ1MkbGFiZWwgPC0gIkNJIG5vdCBvdmVybGFwcGluZyB6ZXJvIgoKIyMKCk1ldGFtZXRhX0ZpZ1MyX2ZlbWFsZS5zaWcgPC0gb3ZlcmFsbDQuZmVtYWxlLnNpZ1MgJT4lCiAgZ2dwbG90KGFlcyh5ID0gR3JvdXBpbmdUZXJtLCB4ID0gdmFsdWUpKSArCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKAogICAgeG1pbiA9IGNpLmxvdywKICAgIHhtYXggPSBjaS5oaWdoCiAgKSwKICBoZWlnaHQgPSAwLjEsIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHBhcmFtZXRlciksCiAgICBmaWxsID0gInNhbG1vbjEiLCBjb2xvciA9ICJzYWxtb24xIiwgc2l6ZSA9IDIuMiwKICAgIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBsaW1pdHMgPSBjKC0wLjQsIDApLAogICAgYnJlYWtzID0gYygtMC4zLCAwKSwKICAgIG5hbWUgPSAiRWZmZWN0IHNpemUiCiAgKSArCiAgZ2VvbV92bGluZSgKICAgIHhpbnRlcmNlcHQgPSAwLAogICAgY29sb3IgPSAiYmxhY2siLAogICAgbGluZXR5cGUgPSAiZGFzaGVkIgogICkgKwogIGZhY2V0X2dyaWQoCiAgICBjb2xzID0gdmFycyhwYXJhbWV0ZXIpLCAjIHJvd3MgPSB2YXJzKGxhYmVsKSwKICAgICMgbGFiZWxsZXIgPSBsYWJlbF93cmFwX2dlbih3aWR0aCA9IDIzKSwKICAgIHNjYWxlcyA9ICJmcmVlIiwKICAgIHNwYWNlID0gImZyZWUiCiAgKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNzAsIHNpemUgPSAxMCwgbWFyZ2luID0gbWFyZ2luKHQgPSAxNSwgciA9IDE1LCBiID0gMTUsIGwgPSAxNSkpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9IE5VTEwsIGxpbmV0eXBlID0gImJsYW5rIiwgZmlsbCA9ICJncmF5OTAiKSwKICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG91ciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG9yID0gImdyYXk5NSIpLAogICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKIyBNZXRhbWV0YV9GaWdTMl9mZW1hbGUuc2lnCmBgYAoKI01ldGFtZXRhX0ZpZ1MyX21hbGUuc2lnIChGaWd1cmUgNUIgcmlnaHQgcGFuZWwpCgpSZXN0cnVjdHVyZSBNQUxFIGRhdGEgZm9yIHBsb3R0aW5nIAoKYGBge3J9Cm92ZXJhbGwzLm1hbGUuc2lnUyA8LSBnYXRoZXIob3ZlcmFsbC5tYWxlLnBsb3QzLCBwYXJhbWV0ZXIsIHZhbHVlLCBjKGxuQ1ZSLCBsblZSLCBsblJSKSwgZmFjdG9yX2tleSA9IFRSVUUpCgoKbG5DVlIuY2kgPC0gb3ZlcmFsbDMubWFsZS5zaWdTICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImxuQ1ZSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuQ1ZSX2xvd2VyLCBjaS5oaWdoID0gbG5DVlJfdXBwZXIpCmxuVlIuY2kgPC0gb3ZlcmFsbDMubWFsZS5zaWdTICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImxuVlIiKSAlPiUKICBtdXRhdGUoY2kubG93ID0gbG5WUl9sb3dlciwgY2kuaGlnaCA9IGxuVlJfdXBwZXIpCmxuUlIuY2kgPC0gb3ZlcmFsbDMubWFsZS5zaWdTICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImxuUlIiKSAlPiUKICBtdXRhdGUoY2kubG93ID0gbG5SUl9sb3dlciwgY2kuaGlnaCA9IGxuUlJfdXBwZXIpCgpvdmVyYWxsNC5tYWxlLnNpZ1MgPC0gYmluZF9yb3dzKGxuQ1ZSLmNpLCBsblZSLmNpLCBsblJSLmNpKSAlPiUgc2VsZWN0KEdyb3VwaW5nVGVybSwgcGFyYW1ldGVyLCB2YWx1ZSwgY2kubG93LCBjaS5oaWdoKQoKb3ZlcmFsbDQubWFsZS5zaWdTJGxhYmVsIDwtICJDSSBub3Qgb3ZlcmxhcHBpbmcgemVybyIKYGBgCgpQbG90IEZpZ1MyIGFsbCBzaWduaWZpY2FudCByZXN1bHRzIChDSSBub3Qgb3ZlcmxhcHBpbmcgemVybywgbWFsZSApCgpgYGB7cn0KTWV0YW1ldGFfRmlnUzJfbWFsZS5zaWcgPC0gb3ZlcmFsbDQubWFsZS5zaWdTICU+JQogIGdncGxvdChhZXMoeSA9IEdyb3VwaW5nVGVybSwgeCA9IHZhbHVlKSkgKwogIGdlb21fZXJyb3JiYXJoKGFlcygKICAgIHhtaW4gPSBjaS5sb3csCiAgICB4bWF4ID0gY2kuaGlnaAogICksCiAgaGVpZ2h0ID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBwYXJhbWV0ZXIpLAogICAgZmlsbCA9ICJtZWRpdW1hcXVhbWFyaW5lIiwgY29sb3IgPSAibWVkaXVtYXF1YW1hcmluZSIsIHNpemUgPSAyLjIsCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbGltaXRzID0gYygwLCAwLjQpLAogICAgYnJlYWtzID0gYygwLCAwLjMpLAogICAgbmFtZSA9ICJFZmZlY3Qgc2l6ZSIKICApICsKICBnZW9tX3ZsaW5lKAogICAgeGludGVyY2VwdCA9IDAsCiAgICBjb2xvciA9ICJibGFjayIsCiAgICBsaW5ldHlwZSA9ICJkYXNoZWQiCiAgKSArCiAgZmFjZXRfZ3JpZCgKICAgIGNvbHMgPSB2YXJzKHBhcmFtZXRlciksIHJvd3MgPSB2YXJzKGxhYmVsKSwKICAgIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSAyMyksCiAgICBzY2FsZXMgPSAiZnJlZSIsCiAgICBzcGFjZSA9ICJmcmVlIgogICkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjcwLCBzaXplID0gMTAsIG1hcmdpbiA9IG1hcmdpbih0ID0gMTUsIHIgPSAxNSwgYiA9IDE1LCBsID0gMTUpKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOVUxMLCBsaW5ldHlwZSA9ICJibGFuayIsIGZpbGwgPSAiZ3JheTkwIiksCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvdXIgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgTWV0YW1ldGFfRmlnUzJfbWFsZS5zaWcKYGBgCgojIyMgMTAgJSBQZXJjIHNleCBkaWZmZXJlbmNlLCBtYWxlIGJpYXMKUmVzdHJ1Y3R1cmUgZGF0YSBmb3IgcGxvdHRpbmcgOiBNYWxlIGJpYXNlZCwgMTAlIGRpZmZlcmVuY2UKCmBgYHtyfQpvdmVyYWxsM1MucGVyYyA8LSBnYXRoZXIob3ZlcmFsbC5tYWxlLnBsb3QzLnBlcmMsIHBhcmFtZXRlciwgdmFsdWUsIGMobG5DVlIsIGxuVlIsIGxuUlIpLCBmYWN0b3Jfa2V5ID0gVFJVRSkgIyBsblZSLAoKbG5DVlIuY2kgPC0gb3ZlcmFsbDNTLnBlcmMgJT4lCiAgZmlsdGVyKHBhcmFtZXRlciA9PSAibG5DVlIiKSAlPiUKICBtdXRhdGUoY2kubG93ID0gbG5DVlJfbG93ZXIsIGNpLmhpZ2ggPSBsbkNWUl91cHBlcikKbG5WUi5jaSA8LSBvdmVyYWxsM1MucGVyYyAlPiUKICBmaWx0ZXIocGFyYW1ldGVyID09ICJsblZSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuVlJfbG93ZXIsIGNpLmhpZ2ggPSBsblZSX3VwcGVyKQpsblJSLmNpIDwtIG92ZXJhbGwzUy5wZXJjICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImxuUlIiKSAlPiUKICBtdXRhdGUoY2kubG93ID0gbG5SUl9sb3dlciwgY2kuaGlnaCA9IGxuUlJfdXBwZXIpCgpvdmVyYWxsNFMubWFsZS5wZXJjIDwtIGJpbmRfcm93cyhsbkNWUi5jaSwgbG5WUi5jaSwgbG5SUi5jaSkgJT4lIHNlbGVjdChHcm91cGluZ1Rlcm0sIHBhcmFtZXRlciwgdmFsdWUsIGNpLmxvdywgY2kuaGlnaCkgIyBsblZSLmNpLAoKb3ZlcmFsbDRTLm1hbGUucGVyYyRsYWJlbCA8LSAiU2V4IGRpZmZlcmVuY2UgaW4gbS9mIHJhdGlvcyA+IDEwJSIKCm92ZXJhbGw0Uy5tYWxlLnBlcmMkdmFsdWUgPC0gYXMubnVtZXJpYyhvdmVyYWxsNFMubWFsZS5wZXJjJHZhbHVlKQpvdmVyYWxsNFMubWFsZS5wZXJjJGNpLmxvdyA8LSBhcy5udW1lcmljKG92ZXJhbGw0Uy5tYWxlLnBlcmMkY2kubG93KQpvdmVyYWxsNFMubWFsZS5wZXJjJGNpLmhpZ2ggPC0gYXMubnVtZXJpYyhvdmVyYWxsNFMubWFsZS5wZXJjJGNpLmhpZ2gpCmBgYAoKUGxvdCBGaWdTMiAgYWxsID4xMCUgZGlmZmVyZW5jZSAobWFsZSBiaWFzKQoKYGBge3J9Ck1ldGFtZXRhX0ZpZ1MyX21hbGUucGVyYyA8LSBvdmVyYWxsNFMubWFsZS5wZXJjICU+JSAjIGZpbHRlciguLCBHcm91cGluZ1Rlcm0gIT0gIkhlYXJpbmciKSAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBHcm91cGluZ1Rlcm0sIHggPSB2YWx1ZSkpICsKICBnZW9tX2Vycm9yYmFyaChhZXMoCiAgICB4bWluID0gY2kubG93LAogICAgeG1heCA9IGNpLmhpZ2gKICApLAogIGhlaWdodCA9IDAuMSwgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIGdlb21fcG9pbnQoYWVzKAogICAgc2hhcGUgPSBwYXJhbWV0ZXIsCiAgICBmaWxsID0gcGFyYW1ldGVyCiAgKSwKICBjb2xvciA9ICJtZWRpdW1hcXVhbWFyaW5lIiwgc2l6ZSA9IDIuMiwKICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbGltaXRzID0gYygtMC4yLCAwLjYyKSwKICAgIGJyZWFrcyA9IGMoMCwgMC4zKSwKICAgIG5hbWUgPSAiRWZmZWN0IHNpemUiCiAgKSArCiAgZ2VvbV92bGluZSgKICAgIHhpbnRlcmNlcHQgPSAwLAogICAgY29sb3IgPSAiYmxhY2siLAogICAgbGluZXR5cGUgPSAiZGFzaGVkIgogICkgKwogIGZhY2V0X2dyaWQoCiAgICBjb2xzID0gdmFycyhwYXJhbWV0ZXIpLCByb3dzID0gdmFycyhsYWJlbCksCiAgICBsYWJlbGxlciA9IGxhYmVsX3dyYXBfZ2VuKHdpZHRoID0gMjMpLAogICAgc2NhbGVzID0gImZyZWUiLAogICAgc3BhY2UgPSAiZnJlZSIKICApICsKICB0aGVtZV9idygpICsKICB0aGVtZSgKICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDI3MCwgc2l6ZSA9IDEwLCBtYXJnaW4gPSBtYXJnaW4odCA9IDE1LCByID0gMTUsIGIgPSAxNSwgbCA9IDE1KSksCiAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9IE5VTEwsIGxpbmV0eXBlID0gImJsYW5rIiwgZmlsbCA9ICJncmF5OTAiKSwKICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG91ciA9ICJncmF5OTUiKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG9yID0gImdyYXk5NSIpLAogICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTQpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKIyBNZXRhbWV0YV9GaWdTMl9tYWxlLnBlcmMgKEZpZ3VyZSA1RCByaWdodCBwYW5lbCkKYGBgCgpSZXN0cnVjdHVyZSBkYXRhIGZvciBwbG90dGluZzogCkZlbWFsZSBiaWFzLCAxMCBwZXJjZW50IGRpZmZlcmVuY2UsIGluY2x1ZGluZyBWUgoKYGBge3J9Cm92ZXJhbGwzUy5wZXJjIDwtIGdhdGhlcihvdmVyYWxsLnBsb3QzLnBlcmMsIHBhcmFtZXRlciwgdmFsdWUsIGMobG5DVlIsIGxuVlIsIGxuUlIpLCBmYWN0b3Jfa2V5ID0gVFJVRSkgIyBsblZSLAoKbG5DVlIuY2kgPC0gb3ZlcmFsbDNTLnBlcmMgJT4lCiAgZmlsdGVyKHBhcmFtZXRlciA9PSAibG5DVlIiKSAlPiUKICBtdXRhdGUoY2kubG93ID0gbG5DVlJfbG93ZXIsIGNpLmhpZ2ggPSBsbkNWUl91cHBlcikKbG5WUi5jaSA8LSBvdmVyYWxsM1MucGVyYyAlPiUKICBmaWx0ZXIocGFyYW1ldGVyID09ICJsblZSIikgJT4lCiAgbXV0YXRlKGNpLmxvdyA9IGxuVlJfbG93ZXIsIGNpLmhpZ2ggPSBsblZSX3VwcGVyKQpsblJSLmNpIDwtIG92ZXJhbGwzUy5wZXJjICU+JQogIGZpbHRlcihwYXJhbWV0ZXIgPT0gImxuUlIiKSAlPiUKICBtdXRhdGUoY2kubG93ID0gbG5SUl9sb3dlciwgY2kuaGlnaCA9IGxuUlJfdXBwZXIpCgpvdmVyYWxsNFMucGVyYyA8LSBiaW5kX3Jvd3MobG5DVlIuY2ksIGxuVlIuY2ksIGxuUlIuY2kpICU+JSBzZWxlY3QoR3JvdXBpbmdUZXJtLCBwYXJhbWV0ZXIsIHZhbHVlLCBjaS5sb3csIGNpLmhpZ2gpCgpvdmVyYWxsNFMucGVyYyRsYWJlbCA8LSAiU2V4IGRpZmZlcmVuY2UgaW4gbS9mIHJhdGlvcyA+IDEwJSIKCm92ZXJhbGw0Uy5wZXJjJHZhbHVlIDwtIGFzLm51bWVyaWMob3ZlcmFsbDRTLnBlcmMkdmFsdWUpCm92ZXJhbGw0Uy5wZXJjJGNpLmxvdyA8LSBhcy5udW1lcmljKG92ZXJhbGw0Uy5wZXJjJGNpLmxvdykKb3ZlcmFsbDRTLnBlcmMkY2kuaGlnaCA8LSBhcy5udW1lcmljKG92ZXJhbGw0Uy5wZXJjJGNpLmhpZ2gpCmBgYAoKUGxvdCBGaWc1RCBhbGwgPjEwJSBkaWZmZXJlbmNlIChmZW1hbGUpCgpgYGB7cn0KTWV0YW1ldGFfRmlnM1NfZmVtYWxlLnBlcmMgPC0gb3ZlcmFsbDRTLnBlcmMgJT4lCiAgZ2dwbG90KGFlcyh5ID0gR3JvdXBpbmdUZXJtLCB4ID0gdmFsdWUpKSArCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKAogICAgeG1pbiA9IGNpLmxvdywKICAgIHhtYXggPSBjaS5oaWdoCiAgKSwKICBoZWlnaHQgPSAwLjEsIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHBhcmFtZXRlciksCiAgICBmaWxsID0gInNhbG1vbjEiLCBjb2xvciA9ICJzYWxtb24xIiwgc2l6ZSA9IDIuMiwKICAgIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKCiAgIyBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0KCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbGltaXRzID0gYygtMC41MywgMC4yKSwKICAgIGJyZWFrcyA9IGMoLTAuMywgMCksCiAgICBuYW1lID0gIkVmZmVjdCBzaXplIgogICkgKwogIGdlb21fdmxpbmUoCiAgICB4aW50ZXJjZXB0ID0gMCwKICAgIGNvbG9yID0gImJsYWNrIiwKICAgIGxpbmV0eXBlID0gImRhc2hlZCIKICApICsKICBmYWNldF9ncmlkKAogICAgY29scyA9IHZhcnMocGFyYW1ldGVyKSwgIyByb3dzID0gdmFycyhsYWJlbCksCiAgICAjIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSAyMyksCiAgICBzY2FsZXMgPSAiZnJlZSIsCiAgICBzcGFjZSA9ICJmcmVlIgogICkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjcwLCBzaXplID0gMTAsIG1hcmdpbiA9IG1hcmdpbih0ID0gMTUsIHIgPSAxNSwgYiA9IDE1LCBsID0gMTUpKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gTlVMTCwgbGluZXR5cGUgPSAiYmxhbmsiLCBmaWxsID0gImdyYXk5MCIpLAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC41LCAibGluZXMiKSwKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZSgpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9saW5lKGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3VyID0gImdyYXk5NSIpLAogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3IgPSAiZ3JheTk1IiksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkKICApCgojIE1ldGFtZXRhX0ZpZzNTX2ZlbWFsZS5wZXJjIChGaWd1cmUgNUQgbGVmdCBwYW5lbCkKYGBgCgpGaWd1cmUgUzIgCgpgYGB7cn0KRmlnUzJjIDwtIGdnYXJyYW5nZShNZXRhbWV0YV9GaWdTMl9mZW1hbGUuc2lnLCBNZXRhbWV0YV9GaWdTMl9tYWxlLnNpZywKICBuY29sID0gMiwgbnJvdyA9IDEsIHdpZHRocyA9IGMoMSwgMS4yMCksIGhlaWdodHMgPSBjKDEsIDEpCikKCkZpZ1MyZCA8LSBnZ2FycmFuZ2UoTWV0YW1ldGFfRmlnM1NfZmVtYWxlLnBlcmMsIE1ldGFtZXRhX0ZpZ1MyX21hbGUucGVyYywKICBuY29sID0gMiwgbnJvdyA9IDEsIHdpZHRocyA9IGMoMSwgMS4yMCksIGhlaWdodHMgPSBjKDEsIDEpCikKCiMgZW5kIGNvbWJpbmF0aW9uIEZpZ3VyZSA1CgpGaWdTMiA8LSBnZ2FycmFuZ2UobWFsZWJpYXNfRmlnUzJfc2lndHJhaXRzLCBtYWxlYmlhc19GaWdTMl9vdmVyMTAsIEZpZ1MyYywgRmlnUzJkLCBuY29sID0gMSwgbnJvdyA9IDQsIGhlaWdodHMgPSBjKDIuMiwgMiwgMi4yLCAyKSwgbGFiZWxzID0gYygiQSIsICIgIiwgIkIiLCAiICIpKQpGaWdTMgpgYGAKCiMjIEFja25vd2xlZGdlbWVudHMKdGJkCgojIyBSIFNlc3Npb24gSW5mb3JtYXRpb24KCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoK